@graphty/graph-io 0.3.25 → 0.3.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (581) hide show
  1. package/README.md +49 -414
  2. package/dist/chunks/children-CL3Cy0ez.js.map +1 -1
  3. package/dist/chunks/choose-BbJI55dx.js +56 -0
  4. package/dist/chunks/choose-BbJI55dx.js.map +1 -0
  5. package/dist/chunks/constants-BCsFsMj4.js +231 -0
  6. package/dist/chunks/constants-BCsFsMj4.js.map +1 -0
  7. package/dist/chunks/{escape-B-tkk_Cl.js → escape-D0g6NNUy.js} +382 -92
  8. package/dist/chunks/escape-D0g6NNUy.js.map +1 -0
  9. package/dist/chunks/export-BTI4yQgy.js +4333 -0
  10. package/dist/chunks/export-BTI4yQgy.js.map +1 -0
  11. package/dist/chunks/exporter-BMqk5oxW.js +3465 -0
  12. package/dist/chunks/exporter-BMqk5oxW.js.map +1 -0
  13. package/dist/chunks/{importer-eUREhBGj.js → exporter-Cra2GYcN.js} +4969 -3201
  14. package/dist/chunks/exporter-Cra2GYcN.js.map +1 -0
  15. package/dist/chunks/{exporter-BGrsWamJ.js → exporter-Dxh231ZF.js} +38 -229
  16. package/dist/chunks/exporter-Dxh231ZF.js.map +1 -0
  17. package/dist/chunks/{exporter-DIeGJXAZ.js → exporter-tne475KK.js} +22 -20
  18. package/dist/chunks/exporter-tne475KK.js.map +1 -0
  19. package/dist/chunks/importer-90YWhJoF.js +2811 -0
  20. package/dist/chunks/importer-90YWhJoF.js.map +1 -0
  21. package/dist/chunks/{importer-D_e7e7LX.js → importer-Bcl1d4xH.js} +398 -145
  22. package/dist/chunks/importer-Bcl1d4xH.js.map +1 -0
  23. package/dist/chunks/{importer-BWY2FFc5.js → importer-BfIsp1f9.js} +255 -77
  24. package/dist/chunks/importer-BfIsp1f9.js.map +1 -0
  25. package/dist/chunks/{importer-zGLo8Dg_.js → importer-C_TEA1zJ.js} +484 -157
  26. package/dist/chunks/importer-C_TEA1zJ.js.map +1 -0
  27. package/dist/chunks/{importer-DET1tg6s.js → importer-DCjOvO7U.js} +1687 -310
  28. package/dist/chunks/importer-DCjOvO7U.js.map +1 -0
  29. package/dist/chunks/{importer-vi3bSdtw.js → importer-DfVu6j59.js} +509 -76
  30. package/dist/chunks/importer-DfVu6j59.js.map +1 -0
  31. package/dist/chunks/{importer-DIrbbnAf.js → importer-Dku_VAIY.js} +585 -226
  32. package/dist/chunks/importer-Dku_VAIY.js.map +1 -0
  33. package/dist/chunks/json-elements-3tnyt5uZ.js +1225 -0
  34. package/dist/chunks/json-elements-3tnyt5uZ.js.map +1 -0
  35. package/dist/chunks/ontology-export-B9Tcf37D.js +357 -0
  36. package/dist/chunks/ontology-export-B9Tcf37D.js.map +1 -0
  37. package/dist/chunks/{records-dbRkxwaq.js → records-CQXT__mY.js} +298 -114
  38. package/dist/chunks/records-CQXT__mY.js.map +1 -0
  39. package/dist/chunks/{text-Dr0Ifpag.js → text-DmcUs5_Q.js} +29 -11
  40. package/dist/chunks/text-DmcUs5_Q.js.map +1 -0
  41. package/dist/chunks/{writer-C7flM-Ih.js → writer-DxjgHwSe.js} +19 -1
  42. package/dist/chunks/writer-DxjgHwSe.js.map +1 -0
  43. package/dist/csv.js +951 -261
  44. package/dist/csv.js.map +1 -1
  45. package/dist/cx.js +6 -3
  46. package/dist/cx2.js +2 -2
  47. package/dist/cys.js +6 -3
  48. package/dist/dot.js +1 -1
  49. package/dist/gexf.js +554 -122
  50. package/dist/gexf.js.map +1 -1
  51. package/dist/gml.js +342 -85
  52. package/dist/gml.js.map +1 -1
  53. package/dist/graph-io.js +1105 -213
  54. package/dist/graph-io.js.map +1 -1
  55. package/dist/graphml.js +3 -2
  56. package/dist/graphml.js.map +1 -1
  57. package/dist/json.js +3 -2
  58. package/dist/neo4j.js +564 -157
  59. package/dist/neo4j.js.map +1 -1
  60. package/dist/obo.js +6 -3
  61. package/dist/pajek.js +1 -1
  62. package/dist/src/children.d.ts +18 -6
  63. package/dist/src/children.d.ts.map +1 -1
  64. package/dist/src/children.js +6 -3
  65. package/dist/src/children.js.map +1 -1
  66. package/dist/src/common/attributes.d.ts +29 -11
  67. package/dist/src/common/attributes.d.ts.map +1 -1
  68. package/dist/src/common/attributes.js +25 -7
  69. package/dist/src/common/attributes.js.map +1 -1
  70. package/dist/src/common/cell-budget.d.ts +9 -2
  71. package/dist/src/common/cell-budget.d.ts.map +1 -1
  72. package/dist/src/common/cell-budget.js +11 -3
  73. package/dist/src/common/cell-budget.js.map +1 -1
  74. package/dist/src/common/choose.d.ts +19 -0
  75. package/dist/src/common/choose.d.ts.map +1 -0
  76. package/dist/src/common/choose.js +72 -0
  77. package/dist/src/common/choose.js.map +1 -0
  78. package/dist/src/common/codes.d.ts +456 -66
  79. package/dist/src/common/codes.d.ts.map +1 -1
  80. package/dist/src/common/codes.js +458 -66
  81. package/dist/src/common/codes.js.map +1 -1
  82. package/dist/src/common/compare.d.ts +81 -0
  83. package/dist/src/common/compare.d.ts.map +1 -0
  84. package/dist/src/common/compare.js +394 -0
  85. package/dist/src/common/compare.js.map +1 -0
  86. package/dist/src/common/cx-export.d.ts +123 -0
  87. package/dist/src/common/cx-export.d.ts.map +1 -0
  88. package/dist/src/common/cx-export.js +334 -0
  89. package/dist/src/common/cx-export.js.map +1 -0
  90. package/dist/src/common/declared-types.d.ts +22 -2
  91. package/dist/src/common/declared-types.d.ts.map +1 -1
  92. package/dist/src/common/declared-types.js +19 -1
  93. package/dist/src/common/declared-types.js.map +1 -1
  94. package/dist/src/common/direction.d.ts +74 -50
  95. package/dist/src/common/direction.d.ts.map +1 -1
  96. package/dist/src/common/direction.js +47 -27
  97. package/dist/src/common/direction.js.map +1 -1
  98. package/dist/src/common/escape.d.ts +21 -9
  99. package/dist/src/common/escape.d.ts.map +1 -1
  100. package/dist/src/common/escape.js +33 -17
  101. package/dist/src/common/escape.js.map +1 -1
  102. package/dist/src/common/export.d.ts +144 -32
  103. package/dist/src/common/export.d.ts.map +1 -1
  104. package/dist/src/common/export.js +216 -42
  105. package/dist/src/common/export.js.map +1 -1
  106. package/dist/src/common/format.d.ts +23 -1
  107. package/dist/src/common/format.d.ts.map +1 -1
  108. package/dist/src/common/format.js +26 -1
  109. package/dist/src/common/format.js.map +1 -1
  110. package/dist/src/common/ids.d.ts +9 -2
  111. package/dist/src/common/ids.d.ts.map +1 -1
  112. package/dist/src/common/ids.js +6 -2
  113. package/dist/src/common/ids.js.map +1 -1
  114. package/dist/src/common/input.d.ts +122 -28
  115. package/dist/src/common/input.d.ts.map +1 -1
  116. package/dist/src/common/input.js +890 -124
  117. package/dist/src/common/input.js.map +1 -1
  118. package/dist/src/common/json-elements.d.ts +144 -20
  119. package/dist/src/common/json-elements.d.ts.map +1 -1
  120. package/dist/src/common/json-elements.js +868 -188
  121. package/dist/src/common/json-elements.js.map +1 -1
  122. package/dist/src/common/line-format.d.ts +90 -0
  123. package/dist/src/common/line-format.d.ts.map +1 -0
  124. package/dist/src/common/line-format.js +185 -0
  125. package/dist/src/common/line-format.js.map +1 -0
  126. package/dist/src/common/lists.d.ts +6 -1
  127. package/dist/src/common/lists.d.ts.map +1 -1
  128. package/dist/src/common/lists.js +2 -0
  129. package/dist/src/common/lists.js.map +1 -1
  130. package/dist/src/common/ontology-export.d.ts +167 -0
  131. package/dist/src/common/ontology-export.d.ts.map +1 -0
  132. package/dist/src/common/ontology-export.js +359 -0
  133. package/dist/src/common/ontology-export.js.map +1 -0
  134. package/dist/src/common/ontology.d.ts +25 -3
  135. package/dist/src/common/ontology.d.ts.map +1 -1
  136. package/dist/src/common/ontology.js +30 -9
  137. package/dist/src/common/ontology.js.map +1 -1
  138. package/dist/src/common/options.d.ts +62 -12
  139. package/dist/src/common/options.d.ts.map +1 -1
  140. package/dist/src/common/options.js +89 -11
  141. package/dist/src/common/options.js.map +1 -1
  142. package/dist/src/common/plural.d.ts +31 -0
  143. package/dist/src/common/plural.d.ts.map +1 -0
  144. package/dist/src/common/plural.js +46 -0
  145. package/dist/src/common/plural.js.map +1 -0
  146. package/dist/src/common/report.d.ts +72 -14
  147. package/dist/src/common/report.d.ts.map +1 -1
  148. package/dist/src/common/report.js +146 -22
  149. package/dist/src/common/report.js.map +1 -1
  150. package/dist/src/common/temporal.d.ts +22 -5
  151. package/dist/src/common/temporal.d.ts.map +1 -1
  152. package/dist/src/common/temporal.js +13 -2
  153. package/dist/src/common/temporal.js.map +1 -1
  154. package/dist/src/common/text.d.ts +39 -23
  155. package/dist/src/common/text.d.ts.map +1 -1
  156. package/dist/src/common/text.js +51 -21
  157. package/dist/src/common/text.js.map +1 -1
  158. package/dist/src/common/weights.d.ts +37 -4
  159. package/dist/src/common/weights.d.ts.map +1 -1
  160. package/dist/src/common/weights.js +61 -2
  161. package/dist/src/common/weights.js.map +1 -1
  162. package/dist/src/common/writer.d.ts +19 -3
  163. package/dist/src/common/writer.d.ts.map +1 -1
  164. package/dist/src/common/writer.js +30 -2
  165. package/dist/src/common/writer.js.map +1 -1
  166. package/dist/src/common/xml.d.ts +125 -9
  167. package/dist/src/common/xml.d.ts.map +1 -1
  168. package/dist/src/common/xml.js +400 -83
  169. package/dist/src/common/xml.js.map +1 -1
  170. package/dist/src/common/zip.d.ts +44 -4
  171. package/dist/src/common/zip.d.ts.map +1 -1
  172. package/dist/src/common/zip.js +134 -5
  173. package/dist/src/common/zip.js.map +1 -1
  174. package/dist/src/formats/csv/exporter.d.ts +80 -24
  175. package/dist/src/formats/csv/exporter.d.ts.map +1 -1
  176. package/dist/src/formats/csv/exporter.js +145 -32
  177. package/dist/src/formats/csv/exporter.js.map +1 -1
  178. package/dist/src/formats/csv/header.d.ts +38 -9
  179. package/dist/src/formats/csv/header.d.ts.map +1 -1
  180. package/dist/src/formats/csv/header.js +46 -10
  181. package/dist/src/formats/csv/header.js.map +1 -1
  182. package/dist/src/formats/csv/importer.d.ts +187 -37
  183. package/dist/src/formats/csv/importer.d.ts.map +1 -1
  184. package/dist/src/formats/csv/importer.js +835 -204
  185. package/dist/src/formats/csv/importer.js.map +1 -1
  186. package/dist/src/formats/csv/index.d.ts +100 -19
  187. package/dist/src/formats/csv/index.d.ts.map +1 -1
  188. package/dist/src/formats/csv/index.js +94 -21
  189. package/dist/src/formats/csv/index.js.map +1 -1
  190. package/dist/src/formats/csv/records.d.ts +95 -10
  191. package/dist/src/formats/csv/records.d.ts.map +1 -1
  192. package/dist/src/formats/csv/records.js +333 -122
  193. package/dist/src/formats/csv/records.js.map +1 -1
  194. package/dist/src/formats/csv/values.d.ts +1 -0
  195. package/dist/src/formats/csv/values.d.ts.map +1 -1
  196. package/dist/src/formats/csv/values.js +1 -0
  197. package/dist/src/formats/csv/values.js.map +1 -1
  198. package/dist/src/formats/cx/exporter.d.ts +102 -0
  199. package/dist/src/formats/cx/exporter.d.ts.map +1 -0
  200. package/dist/src/formats/cx/exporter.js +1217 -0
  201. package/dist/src/formats/cx/exporter.js.map +1 -0
  202. package/dist/src/formats/cx/importer.d.ts +79 -32
  203. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  204. package/dist/src/formats/cx/importer.js +680 -285
  205. package/dist/src/formats/cx/importer.js.map +1 -1
  206. package/dist/src/formats/cx/index.d.ts +4 -3
  207. package/dist/src/formats/cx/index.d.ts.map +1 -1
  208. package/dist/src/formats/cx/index.js +4 -3
  209. package/dist/src/formats/cx/index.js.map +1 -1
  210. package/dist/src/formats/cx2/exporter.d.ts +29 -11
  211. package/dist/src/formats/cx2/exporter.d.ts.map +1 -1
  212. package/dist/src/formats/cx2/exporter.js +39 -268
  213. package/dist/src/formats/cx2/exporter.js.map +1 -1
  214. package/dist/src/formats/cx2/importer.d.ts +78 -28
  215. package/dist/src/formats/cx2/importer.d.ts.map +1 -1
  216. package/dist/src/formats/cx2/importer.js +226 -79
  217. package/dist/src/formats/cx2/importer.js.map +1 -1
  218. package/dist/src/formats/cx2/index.d.ts +2 -1
  219. package/dist/src/formats/cx2/index.d.ts.map +1 -1
  220. package/dist/src/formats/cx2/index.js +2 -1
  221. package/dist/src/formats/cx2/index.js.map +1 -1
  222. package/dist/src/formats/cys/constants.d.ts +66 -17
  223. package/dist/src/formats/cys/constants.d.ts.map +1 -1
  224. package/dist/src/formats/cys/constants.js +59 -18
  225. package/dist/src/formats/cys/constants.js.map +1 -1
  226. package/dist/src/formats/cys/exporter.d.ts +118 -0
  227. package/dist/src/formats/cys/exporter.d.ts.map +1 -0
  228. package/dist/src/formats/cys/exporter.js +1072 -0
  229. package/dist/src/formats/cys/exporter.js.map +1 -0
  230. package/dist/src/formats/cys/importer.d.ts +22 -8
  231. package/dist/src/formats/cys/importer.d.ts.map +1 -1
  232. package/dist/src/formats/cys/importer.js +510 -149
  233. package/dist/src/formats/cys/importer.js.map +1 -1
  234. package/dist/src/formats/cys/index.d.ts +4 -2
  235. package/dist/src/formats/cys/index.d.ts.map +1 -1
  236. package/dist/src/formats/cys/index.js +4 -2
  237. package/dist/src/formats/cys/index.js.map +1 -1
  238. package/dist/src/formats/cys/session.d.ts +46 -7
  239. package/dist/src/formats/cys/session.d.ts.map +1 -1
  240. package/dist/src/formats/cys/session.js +98 -24
  241. package/dist/src/formats/cys/session.js.map +1 -1
  242. package/dist/src/formats/cys/tables.d.ts +9 -2
  243. package/dist/src/formats/cys/tables.d.ts.map +1 -1
  244. package/dist/src/formats/cys/tables.js +29 -7
  245. package/dist/src/formats/cys/tables.js.map +1 -1
  246. package/dist/src/formats/dot/exporter.d.ts +42 -14
  247. package/dist/src/formats/dot/exporter.d.ts.map +1 -1
  248. package/dist/src/formats/dot/exporter.js +56 -29
  249. package/dist/src/formats/dot/exporter.js.map +1 -1
  250. package/dist/src/formats/dot/importer.d.ts +91 -29
  251. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  252. package/dist/src/formats/dot/importer.js +190 -39
  253. package/dist/src/formats/dot/importer.js.map +1 -1
  254. package/dist/src/formats/dot/index.d.ts +2 -1
  255. package/dist/src/formats/dot/index.d.ts.map +1 -1
  256. package/dist/src/formats/dot/index.js +2 -1
  257. package/dist/src/formats/dot/index.js.map +1 -1
  258. package/dist/src/formats/dot/names.d.ts +44 -11
  259. package/dist/src/formats/dot/names.d.ts.map +1 -1
  260. package/dist/src/formats/dot/names.js +44 -11
  261. package/dist/src/formats/dot/names.js.map +1 -1
  262. package/dist/src/formats/dot/tokenizer.d.ts +9 -2
  263. package/dist/src/formats/dot/tokenizer.d.ts.map +1 -1
  264. package/dist/src/formats/dot/tokenizer.js +20 -5
  265. package/dist/src/formats/dot/tokenizer.js.map +1 -1
  266. package/dist/src/formats/gexf/exporter.d.ts +46 -15
  267. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  268. package/dist/src/formats/gexf/exporter.js +45 -15
  269. package/dist/src/formats/gexf/exporter.js.map +1 -1
  270. package/dist/src/formats/gexf/importer.d.ts +87 -23
  271. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  272. package/dist/src/formats/gexf/importer.js +471 -90
  273. package/dist/src/formats/gexf/importer.js.map +1 -1
  274. package/dist/src/formats/gexf/index.d.ts +84 -21
  275. package/dist/src/formats/gexf/index.d.ts.map +1 -1
  276. package/dist/src/formats/gexf/index.js +80 -23
  277. package/dist/src/formats/gexf/index.js.map +1 -1
  278. package/dist/src/formats/gexf/schema.d.ts +67 -15
  279. package/dist/src/formats/gexf/schema.d.ts.map +1 -1
  280. package/dist/src/formats/gexf/schema.js +59 -13
  281. package/dist/src/formats/gexf/schema.js.map +1 -1
  282. package/dist/src/formats/gml/exporter.d.ts +69 -21
  283. package/dist/src/formats/gml/exporter.d.ts.map +1 -1
  284. package/dist/src/formats/gml/exporter.js +74 -29
  285. package/dist/src/formats/gml/exporter.js.map +1 -1
  286. package/dist/src/formats/gml/importer.d.ts +116 -25
  287. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  288. package/dist/src/formats/gml/importer.js +290 -61
  289. package/dist/src/formats/gml/importer.js.map +1 -1
  290. package/dist/src/formats/gml/index.d.ts +87 -24
  291. package/dist/src/formats/gml/index.d.ts.map +1 -1
  292. package/dist/src/formats/gml/index.js +79 -26
  293. package/dist/src/formats/gml/index.js.map +1 -1
  294. package/dist/src/formats/gml/syntax.d.ts +67 -18
  295. package/dist/src/formats/gml/syntax.d.ts.map +1 -1
  296. package/dist/src/formats/gml/syntax.js +108 -26
  297. package/dist/src/formats/gml/syntax.js.map +1 -1
  298. package/dist/src/formats/graphml/constants.d.ts +174 -44
  299. package/dist/src/formats/graphml/constants.d.ts.map +1 -1
  300. package/dist/src/formats/graphml/constants.js +165 -44
  301. package/dist/src/formats/graphml/constants.js.map +1 -1
  302. package/dist/src/formats/graphml/exporter.d.ts +17 -9
  303. package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
  304. package/dist/src/formats/graphml/exporter.js +33 -12
  305. package/dist/src/formats/graphml/exporter.js.map +1 -1
  306. package/dist/src/formats/graphml/importer.d.ts +19 -7
  307. package/dist/src/formats/graphml/importer.d.ts.map +1 -1
  308. package/dist/src/formats/graphml/importer.js +466 -39
  309. package/dist/src/formats/graphml/importer.js.map +1 -1
  310. package/dist/src/formats/graphml/index.d.ts +2 -1
  311. package/dist/src/formats/graphml/index.d.ts.map +1 -1
  312. package/dist/src/formats/graphml/index.js +2 -1
  313. package/dist/src/formats/graphml/index.js.map +1 -1
  314. package/dist/src/formats/graphml/tree.d.ts +6 -2
  315. package/dist/src/formats/graphml/tree.d.ts.map +1 -1
  316. package/dist/src/formats/graphml/tree.js +6 -2
  317. package/dist/src/formats/graphml/tree.js.map +1 -1
  318. package/dist/src/formats/graphml/yfiles.d.ts +8 -3
  319. package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
  320. package/dist/src/formats/graphml/yfiles.js +36 -15
  321. package/dist/src/formats/graphml/yfiles.js.map +1 -1
  322. package/dist/src/formats/json/dialect.d.ts +88 -24
  323. package/dist/src/formats/json/dialect.d.ts.map +1 -1
  324. package/dist/src/formats/json/dialect.js +109 -19
  325. package/dist/src/formats/json/dialect.js.map +1 -1
  326. package/dist/src/formats/json/exporter.d.ts +134 -22
  327. package/dist/src/formats/json/exporter.d.ts.map +1 -1
  328. package/dist/src/formats/json/exporter.js +135 -54
  329. package/dist/src/formats/json/exporter.js.map +1 -1
  330. package/dist/src/formats/json/importer.d.ts +173 -52
  331. package/dist/src/formats/json/importer.d.ts.map +1 -1
  332. package/dist/src/formats/json/importer.js +899 -220
  333. package/dist/src/formats/json/importer.js.map +1 -1
  334. package/dist/src/formats/json/index.d.ts +3 -2
  335. package/dist/src/formats/json/index.d.ts.map +1 -1
  336. package/dist/src/formats/json/index.js +3 -2
  337. package/dist/src/formats/json/index.js.map +1 -1
  338. package/dist/src/formats/json/obographs-export.d.ts +68 -0
  339. package/dist/src/formats/json/obographs-export.d.ts.map +1 -0
  340. package/dist/src/formats/json/obographs-export.js +941 -0
  341. package/dist/src/formats/json/obographs-export.js.map +1 -0
  342. package/dist/src/formats/json/obographs.d.ts +26 -0
  343. package/dist/src/formats/json/obographs.d.ts.map +1 -1
  344. package/dist/src/formats/json/obographs.js +297 -80
  345. package/dist/src/formats/json/obographs.js.map +1 -1
  346. package/dist/src/formats/neo4j/exporter.d.ts +109 -21
  347. package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
  348. package/dist/src/formats/neo4j/exporter.js +238 -85
  349. package/dist/src/formats/neo4j/exporter.js.map +1 -1
  350. package/dist/src/formats/neo4j/header.d.ts +17 -4
  351. package/dist/src/formats/neo4j/header.d.ts.map +1 -1
  352. package/dist/src/formats/neo4j/header.js +36 -4
  353. package/dist/src/formats/neo4j/header.js.map +1 -1
  354. package/dist/src/formats/neo4j/importer.d.ts +107 -27
  355. package/dist/src/formats/neo4j/importer.d.ts.map +1 -1
  356. package/dist/src/formats/neo4j/importer.js +415 -63
  357. package/dist/src/formats/neo4j/importer.js.map +1 -1
  358. package/dist/src/formats/neo4j/index.d.ts +73 -23
  359. package/dist/src/formats/neo4j/index.d.ts.map +1 -1
  360. package/dist/src/formats/neo4j/index.js +65 -25
  361. package/dist/src/formats/neo4j/index.js.map +1 -1
  362. package/dist/src/formats/obo/exporter.d.ts +150 -0
  363. package/dist/src/formats/obo/exporter.d.ts.map +1 -0
  364. package/dist/src/formats/obo/exporter.js +1736 -0
  365. package/dist/src/formats/obo/exporter.js.map +1 -0
  366. package/dist/src/formats/obo/importer.d.ts +95 -19
  367. package/dist/src/formats/obo/importer.d.ts.map +1 -1
  368. package/dist/src/formats/obo/importer.js +475 -104
  369. package/dist/src/formats/obo/importer.js.map +1 -1
  370. package/dist/src/formats/obo/index.d.ts +6 -3
  371. package/dist/src/formats/obo/index.d.ts.map +1 -1
  372. package/dist/src/formats/obo/index.js +6 -3
  373. package/dist/src/formats/obo/index.js.map +1 -1
  374. package/dist/src/formats/obo/syntax.d.ts +108 -4
  375. package/dist/src/formats/obo/syntax.d.ts.map +1 -1
  376. package/dist/src/formats/obo/syntax.js +211 -34
  377. package/dist/src/formats/obo/syntax.js.map +1 -1
  378. package/dist/src/formats/pajek/exporter.d.ts +54 -16
  379. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  380. package/dist/src/formats/pajek/exporter.js +66 -34
  381. package/dist/src/formats/pajek/exporter.js.map +1 -1
  382. package/dist/src/formats/pajek/importer.d.ts +84 -22
  383. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  384. package/dist/src/formats/pajek/importer.js +303 -83
  385. package/dist/src/formats/pajek/importer.js.map +1 -1
  386. package/dist/src/formats/pajek/index.d.ts +2 -1
  387. package/dist/src/formats/pajek/index.d.ts.map +1 -1
  388. package/dist/src/formats/pajek/index.js +2 -1
  389. package/dist/src/formats/pajek/index.js.map +1 -1
  390. package/dist/src/formats/pajek/syntax.d.ts +77 -14
  391. package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
  392. package/dist/src/formats/pajek/syntax.js +183 -51
  393. package/dist/src/formats/pajek/syntax.js.map +1 -1
  394. package/dist/src/formats/xgmml/columns.d.ts +1 -0
  395. package/dist/src/formats/xgmml/columns.d.ts.map +1 -1
  396. package/dist/src/formats/xgmml/columns.js +4 -0
  397. package/dist/src/formats/xgmml/columns.js.map +1 -1
  398. package/dist/src/formats/xgmml/constants.d.ts +186 -56
  399. package/dist/src/formats/xgmml/constants.d.ts.map +1 -1
  400. package/dist/src/formats/xgmml/constants.js +181 -57
  401. package/dist/src/formats/xgmml/constants.js.map +1 -1
  402. package/dist/src/formats/xgmml/document.d.ts +65 -11
  403. package/dist/src/formats/xgmml/document.d.ts.map +1 -1
  404. package/dist/src/formats/xgmml/document.js +157 -28
  405. package/dist/src/formats/xgmml/document.js.map +1 -1
  406. package/dist/src/formats/xgmml/emit.d.ts +61 -3
  407. package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
  408. package/dist/src/formats/xgmml/emit.js +129 -26
  409. package/dist/src/formats/xgmml/emit.js.map +1 -1
  410. package/dist/src/formats/xgmml/exporter.d.ts +13 -6
  411. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
  412. package/dist/src/formats/xgmml/exporter.js +20 -21
  413. package/dist/src/formats/xgmml/exporter.js.map +1 -1
  414. package/dist/src/formats/xgmml/importer.d.ts +33 -12
  415. package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
  416. package/dist/src/formats/xgmml/importer.js +35 -72
  417. package/dist/src/formats/xgmml/importer.js.map +1 -1
  418. package/dist/src/formats/xgmml/index.d.ts +1 -0
  419. package/dist/src/formats/xgmml/index.d.ts.map +1 -1
  420. package/dist/src/formats/xgmml/index.js +1 -0
  421. package/dist/src/formats/xgmml/index.js.map +1 -1
  422. package/dist/src/formats/xgmml/values.d.ts +8 -1
  423. package/dist/src/formats/xgmml/values.d.ts.map +1 -1
  424. package/dist/src/formats/xgmml/values.js +7 -2
  425. package/dist/src/formats/xgmml/values.js.map +1 -1
  426. package/dist/src/index.d.ts +23 -18
  427. package/dist/src/index.d.ts.map +1 -1
  428. package/dist/src/index.js +28 -16
  429. package/dist/src/index.js.map +1 -1
  430. package/dist/src/registry.d.ts +478 -92
  431. package/dist/src/registry.d.ts.map +1 -1
  432. package/dist/src/registry.js +807 -88
  433. package/dist/src/registry.js.map +1 -1
  434. package/dist/src/sniff.d.ts +61 -19
  435. package/dist/src/sniff.d.ts.map +1 -1
  436. package/dist/src/sniff.js +121 -29
  437. package/dist/src/sniff.js.map +1 -1
  438. package/dist/src/types.d.ts +362 -112
  439. package/dist/src/types.d.ts.map +1 -1
  440. package/dist/src/types.js +28 -7
  441. package/dist/src/types.js.map +1 -1
  442. package/dist/xgmml.js +2 -2
  443. package/docs/samples/README.md +25 -0
  444. package/docs/samples/got-edges.csv +353 -0
  445. package/docs/samples/got-network.graphml +1384 -0
  446. package/docs/samples/got-nodes.csv +108 -0
  447. package/docs/samples/got.cx +930 -0
  448. package/docs/samples/got.cx2 +465 -0
  449. package/docs/samples/got.gexf +471 -0
  450. package/docs/samples/got.gml +2650 -0
  451. package/docs/samples/got.json +2546 -0
  452. package/docs/samples/got.net +461 -0
  453. package/docs/samples/movies-nodes.csv +9 -0
  454. package/docs/samples/movies-rels.csv +8 -0
  455. package/docs/samples/networks.cys +0 -0
  456. package/docs/samples/proteins.xgmml +9 -0
  457. package/docs/samples/teams.gv +24 -0
  458. package/docs/samples/vehicles.obo +25 -0
  459. package/package.json +9 -4
  460. package/src/children.ts +18 -6
  461. package/src/common/attributes.ts +29 -11
  462. package/src/common/cell-budget.ts +11 -3
  463. package/src/common/choose.ts +89 -0
  464. package/src/common/codes.ts +490 -66
  465. package/src/common/compare.ts +472 -0
  466. package/src/common/cx-export.ts +432 -0
  467. package/src/common/declared-types.ts +38 -4
  468. package/src/common/direction.ts +78 -51
  469. package/src/common/escape.ts +33 -17
  470. package/src/common/export.ts +284 -47
  471. package/src/common/format.ts +30 -1
  472. package/src/common/ids.ts +14 -3
  473. package/src/common/input.ts +1057 -134
  474. package/src/common/json-elements.ts +1034 -198
  475. package/src/common/line-format.ts +249 -0
  476. package/src/common/lists.ts +6 -1
  477. package/src/common/ontology-export.ts +461 -0
  478. package/src/common/ontology.ts +31 -9
  479. package/src/common/options.ts +110 -15
  480. package/src/common/plural.ts +49 -0
  481. package/src/common/report.ts +168 -25
  482. package/src/common/temporal.ts +22 -5
  483. package/src/common/text.ts +62 -23
  484. package/src/common/weights.ts +74 -4
  485. package/src/common/writer.ts +37 -3
  486. package/src/common/xml.ts +477 -88
  487. package/src/common/zip.ts +169 -7
  488. package/src/formats/csv/exporter.ts +201 -46
  489. package/src/formats/csv/header.ts +50 -11
  490. package/src/formats/csv/importer.ts +1133 -245
  491. package/src/formats/csv/index.ts +106 -19
  492. package/src/formats/csv/records.ts +396 -122
  493. package/src/formats/csv/values.ts +1 -0
  494. package/src/formats/cx/exporter.ts +1483 -0
  495. package/src/formats/cx/importer.ts +888 -300
  496. package/src/formats/cx/index.ts +4 -3
  497. package/src/formats/cx2/exporter.ts +61 -338
  498. package/src/formats/cx2/importer.ts +317 -86
  499. package/src/formats/cx2/index.ts +2 -1
  500. package/src/formats/cys/constants.ts +62 -17
  501. package/src/formats/cys/exporter.ts +1368 -0
  502. package/src/formats/cys/importer.ts +659 -157
  503. package/src/formats/cys/index.ts +4 -2
  504. package/src/formats/cys/session.ts +139 -31
  505. package/src/formats/cys/tables.ts +47 -9
  506. package/src/formats/dot/exporter.ts +83 -37
  507. package/src/formats/dot/importer.ts +248 -54
  508. package/src/formats/dot/index.ts +2 -1
  509. package/src/formats/dot/names.ts +44 -11
  510. package/src/formats/dot/tokenizer.ts +25 -6
  511. package/src/formats/gexf/exporter.ts +57 -18
  512. package/src/formats/gexf/importer.ts +636 -105
  513. package/src/formats/gexf/index.ts +90 -21
  514. package/src/formats/gexf/schema.ts +67 -15
  515. package/src/formats/gml/exporter.ts +90 -36
  516. package/src/formats/gml/importer.ts +388 -67
  517. package/src/formats/gml/index.ts +85 -24
  518. package/src/formats/gml/syntax.ts +111 -26
  519. package/src/formats/graphml/constants.ts +178 -44
  520. package/src/formats/graphml/exporter.ts +52 -18
  521. package/src/formats/graphml/importer.ts +640 -60
  522. package/src/formats/graphml/index.ts +2 -1
  523. package/src/formats/graphml/tree.ts +6 -2
  524. package/src/formats/graphml/yfiles.ts +37 -15
  525. package/src/formats/json/dialect.ts +128 -29
  526. package/src/formats/json/exporter.ts +205 -68
  527. package/src/formats/json/importer.ts +1163 -253
  528. package/src/formats/json/index.ts +3 -1
  529. package/src/formats/json/obographs-export.ts +1197 -0
  530. package/src/formats/json/obographs.ts +353 -92
  531. package/src/formats/neo4j/exporter.ts +320 -101
  532. package/src/formats/neo4j/header.ts +44 -6
  533. package/src/formats/neo4j/importer.ts +512 -73
  534. package/src/formats/neo4j/index.ts +75 -23
  535. package/src/formats/obo/exporter.ts +2210 -0
  536. package/src/formats/obo/importer.ts +622 -109
  537. package/src/formats/obo/index.ts +6 -3
  538. package/src/formats/obo/syntax.ts +232 -37
  539. package/src/formats/pajek/exporter.ts +89 -41
  540. package/src/formats/pajek/importer.ts +407 -93
  541. package/src/formats/pajek/index.ts +2 -1
  542. package/src/formats/pajek/syntax.ts +213 -52
  543. package/src/formats/xgmml/columns.ts +10 -0
  544. package/src/formats/xgmml/constants.ts +183 -56
  545. package/src/formats/xgmml/document.ts +212 -34
  546. package/src/formats/xgmml/emit.ts +175 -34
  547. package/src/formats/xgmml/exporter.ts +35 -27
  548. package/src/formats/xgmml/importer.ts +64 -86
  549. package/src/formats/xgmml/index.ts +1 -0
  550. package/src/formats/xgmml/values.ts +11 -3
  551. package/src/index.ts +81 -11
  552. package/src/registry.ts +1121 -135
  553. package/src/sniff.ts +163 -32
  554. package/src/types.ts +385 -114
  555. package/dist/chunks/escape-B-tkk_Cl.js.map +0 -1
  556. package/dist/chunks/export-Bh60Dv-n.js +0 -582
  557. package/dist/chunks/export-Bh60Dv-n.js.map +0 -1
  558. package/dist/chunks/exporter-BGrsWamJ.js.map +0 -1
  559. package/dist/chunks/exporter-DIeGJXAZ.js.map +0 -1
  560. package/dist/chunks/importer-BWY2FFc5.js.map +0 -1
  561. package/dist/chunks/importer-DD-xv9_Y.js +0 -1471
  562. package/dist/chunks/importer-DD-xv9_Y.js.map +0 -1
  563. package/dist/chunks/importer-DET1tg6s.js.map +0 -1
  564. package/dist/chunks/importer-DEcKhsmQ.js +0 -1614
  565. package/dist/chunks/importer-DEcKhsmQ.js.map +0 -1
  566. package/dist/chunks/importer-DIrbbnAf.js.map +0 -1
  567. package/dist/chunks/importer-D_e7e7LX.js.map +0 -1
  568. package/dist/chunks/importer-eUREhBGj.js.map +0 -1
  569. package/dist/chunks/importer-vi3bSdtw.js.map +0 -1
  570. package/dist/chunks/importer-zGLo8Dg_.js.map +0 -1
  571. package/dist/chunks/json-elements-DDS8N2Dd.js +0 -779
  572. package/dist/chunks/json-elements-DDS8N2Dd.js.map +0 -1
  573. package/dist/chunks/ontology-BnrJ4I98.js +0 -113
  574. package/dist/chunks/ontology-BnrJ4I98.js.map +0 -1
  575. package/dist/chunks/records-dbRkxwaq.js.map +0 -1
  576. package/dist/chunks/report-B1z4WT9e.js +0 -2372
  577. package/dist/chunks/report-B1z4WT9e.js.map +0 -1
  578. package/dist/chunks/text-Dr0Ifpag.js.map +0 -1
  579. package/dist/chunks/weights-Dzba96G3.js +0 -176
  580. package/dist/chunks/weights-Dzba96G3.js.map +0 -1
  581. package/dist/chunks/writer-C7flM-Ih.js.map +0 -1
@@ -0,0 +1,4333 @@
1
+ import { GraphFormatError, INVALID_INDEX } from "@graphty/graph-format";
2
+ const FETCH_CODE = "E_FETCH";
3
+ const MISSING_ID_CODE = "E_MISSING_ID";
4
+ const MISSING_ENDPOINT_CODE = "E_MISSING_ENDPOINT";
5
+ const DUPLICATE_NODE_CODE = "W_DUPLICATE_NODE";
6
+ const NO_GRAPH_CODE = "E_NO_GRAPH";
7
+ const MULTIPLE_GRAPHS_CODE = "W_MULTIPLE_GRAPHS";
8
+ const EMPTY_INPUT_CODE = "E_EMPTY_INPUT";
9
+ const SYNTAX_CODE = "E_SYNTAX";
10
+ const XML_SYNTAX_CODE = "E_XML_SYNTAX";
11
+ const UNKNOWN_ELEMENT_CODE = "W_UNKNOWN_ELEMENT";
12
+ const STRAY_TEXT_CODE = "W_STRAY_TEXT";
13
+ const UNKNOWN_PARENT_CODE = "E_UNKNOWN_PARENT";
14
+ const HYPEREDGE_CODE = "E_HYPEREDGE";
15
+ const DUPLICATE_KEY_CODE = "E_DUPLICATE_KEY";
16
+ const COLUMN_RENAMED_CODE = "W_COLUMN_RENAMED";
17
+ const COLUMN_DROPPED_CODE = "W_COLUMN_DROPPED";
18
+ const ROLE_TAKEN_CODE = "W_ROLE_TAKEN";
19
+ const PRECISION_CODE = "W_PRECISION";
20
+ const ID_MERGED_CODE = "W_ID_MERGED";
21
+ const SINK_OPTION_CODE = "W_SINK_OPTION";
22
+ const OPTION_IGNORED_CODE = "W_OPTION_IGNORED";
23
+ const INVALID_UTF8_CODE = "E_INVALID_UTF8";
24
+ const INVALID_ENCODING_CODE = "E_INVALID_ENCODING";
25
+ const ENCODING_FALLBACK_CODE = "W_ENCODING_FALLBACK";
26
+ const UNKNOWN_ENCODING_CODE = "W_UNKNOWN_ENCODING";
27
+ const ENCODING_CONFLICT_CODE = "W_ENCODING_CONFLICT";
28
+ const CONTROL_CHARACTER_CODE = "W_CONTROL_CHARACTER";
29
+ const FOREIGN_FORMAT_CODE = "E_FOREIGN_FORMAT";
30
+ const ISSUES_SUPPRESSED_CODE = "W_ISSUES_SUPPRESSED";
31
+ const UNKNOWN_XML_ATTRIBUTE_CODE = "W_UNKNOWN_XML_ATTRIBUTE";
32
+ const DIRECTION_REFUSED_CODE = "W_DIRECTION_REFUSED";
33
+ const DIRECTION_FORCED_CODE = "W_DIRECTION_FORCED";
34
+ const MIXED_DIRECTION_CODE = "E_MIXED_DIRECTION";
35
+ const COUNT_HINT_CODE = "W_COUNT_HINT";
36
+ const UNKNOWN_ATTR_TYPE_CODE = "W_UNKNOWN_ATTR_TYPE";
37
+ const BAD_DEFAULT_CODE = "W_BAD_DEFAULT";
38
+ const BAD_OPTIONS_CODE = "W_BAD_OPTIONS";
39
+ const DUPLICATE_EDGE_ID_CODE = "E_DUPLICATE_EDGE_ID";
40
+ const BAD_VALUE_CODE = "E_BAD_VALUE";
41
+ const WIDENED_CODE = "W_WIDENED";
42
+ const DANGLING_REFERENCE_CODE = "W_DANGLING_REFERENCE";
43
+ const DUPLICATE_ATTRIBUTE_CODE = "W_DUPLICATE_ATTRIBUTE";
44
+ const PARENT_CYCLE_CODE = "E_PARENT_CYCLE";
45
+ const EQUATION_AS_TEXT_CODE = "W_EQUATION_AS_TEXT";
46
+ const STYLES_NOT_IMPORTED_CODE = "W_STYLES_NOT_IMPORTED";
47
+ const BAD_ASPECT_BLOCK_CODE = "E_BAD_ASPECT_BLOCK";
48
+ const MULTI_ASPECT_FRAGMENT_CODE = "W_MULTI_ASPECT_FRAGMENT";
49
+ const SINGLE_OBJECT_ASPECT_CODE = "W_SINGLE_OBJECT_ASPECT";
50
+ const JSON_NONSTANDARD_NUMBER_CODE = "W_JSON_NONSTANDARD_NUMBER";
51
+ const ASPECT_ORDER_CODE = "W_ASPECT_ORDER";
52
+ const COUNT_MISMATCH_CODE = "W_COUNT_MISMATCH";
53
+ const STATUS_FAILED_CODE = "E_STATUS_FAILED";
54
+ const STATUS_WARNING_CODE = "W_STATUS_WARNING";
55
+ const TOO_LARGE_CODE = "E_TOO_LARGE";
56
+ const COLUMN_TYPE_CODE = "E_COLUMN_TYPE";
57
+ const GRAPH_NOT_FOUND_CODE = "E_GRAPH_NOT_FOUND";
58
+ const AMBIGUOUS_GRAPH_NAME_CODE = "E_AMBIGUOUS_GRAPH_NAME";
59
+ const DUPLICATE_EDGE_CODE = "E_DUPLICATE_EDGE";
60
+ const SELF_LOOP_CODE = "E_SELF_LOOP";
61
+ const EDGES_MERGED_CODE = "W_EDGES_MERGED";
62
+ const SELF_LOOPS_DROPPED_CODE = "W_SELF_LOOPS_DROPPED";
63
+ const UNKNOWN_OPTION_CODE = "W_UNKNOWN_OPTION";
64
+ const BAD_LINE_CODE = "E_BAD_LINE";
65
+ const WEIGHT_NOT_FOUND_CODE = "W_WEIGHT_NOT_FOUND";
66
+ const ROLE_DROPPED_CODE = "W_ROLE_DROPPED";
67
+ const PARENTS_DROPPED_CODE = "W_PARENTS_DROPPED";
68
+ const TEMPORAL_DROPPED_CODE = "W_TEMPORAL_DROPPED";
69
+ const MUTUAL_EXPANDED_CODE = "W_MUTUAL_EXPANDED";
70
+ const MUTUAL_AS_UNDIRECTED_CODE = "W_MUTUAL_AS_UNDIRECTED";
71
+ const ID_TEXT_TYPE_CODE = "W_ID_TEXT_TYPE";
72
+ const ID_TEXT_COLLISION_CODE = "E_ID_TEXT_COLLISION";
73
+ const TEMPORAL_TEXT_DROPPED_CODE = "W_TEMPORAL_TEXT_DROPPED";
74
+ const WEIGHTS_DROPPED_CODE = "W_WEIGHTS_DROPPED";
75
+ const WEIGHT_KEY_CLASH_CODE = "W_WEIGHT_KEY_CLASH";
76
+ const ROLE_ASSUMED_CODE = "W_ROLE_ASSUMED";
77
+ const COLUMN_RENAMED_LOSS_CODE = "W_COLUMN_NAME_CHANGED";
78
+ const EMPTY_COLUMN_DROPPED_CODE = "W_EMPTY_COLUMN_DROPPED";
79
+ const STORAGE_CLASS_CODE = "W_STORAGE_CLASS_CHANGED";
80
+ const INTEGRAL_F64_CODE = "W_INTEGRAL_F64_AS_I32";
81
+ const TEXT_INFERRED_CODE = "W_TEXT_INFERRED";
82
+ const XML_ILLEGAL_CHAR_CODE = "E_XML_ILLEGAL_CHAR";
83
+ const COLUMN_AS_PROPERTY_VALUE_CODE = "W_COLUMN_AS_PROPERTY_VALUE";
84
+ const RELATION_ASSUMED_CODE = "W_RELATION_ASSUMED";
85
+ const TYPEDEF_NODES_CODE = "W_TYPEDEF_NODES";
86
+ const GRAPH_COLUMN_AS_METADATA_CODE = "W_GRAPH_COLUMN_AS_METADATA";
87
+ const DIRECTION_DROPPED_CODE = "W_DIRECTION_DROPPED";
88
+ const NONFINITE_AS_NULL_CODE = "W_NONFINITE_AS_NULL";
89
+ const NODE_ORDER_CODE = "W_NODE_ORDER";
90
+ const OPTIONS_GAINED_CODE = "W_OPTIONS_GAINED";
91
+ const ELEMENT_ISSUE = Object.freeze({
92
+ /** A node id of a type the graph cannot hold (an empty id, a non-finite number, an object). The node is skipped. */
93
+ INVALID_ID: "E_INVALID_ID",
94
+ /** An edge names a node the file never declares, while `addMissingNodes` is false. The edge is skipped. */
95
+ UNKNOWN_NODE: "E_UNKNOWN_NODE",
96
+ /**
97
+ * An edge weight that is not a number (text such as "2,5" with a decimal comma, NaN, a boolean). The whole edge is
98
+ * skipped, not only its weight.
99
+ */
100
+ INVALID_WEIGHT: "E_INVALID_WEIGHT",
101
+ /** A second edge between the same two nodes, while `duplicateEdges` is "error". The edge is skipped. */
102
+ DUPLICATE_EDGE: DUPLICATE_EDGE_CODE,
103
+ /** An edge from a node to itself, while `selfLoops` is "error". The edge is skipped. */
104
+ SELF_LOOP: SELF_LOOP_CODE,
105
+ /** An edge id declared twice. The second edge is skipped. */
106
+ DUPLICATE_EDGE_ID: DUPLICATE_EDGE_ID_CODE
107
+ });
108
+ const INPUT_ISSUE = Object.freeze({
109
+ /** The input is empty or holds only whitespace. The import stops. */
110
+ EMPTY_INPUT: EMPTY_INPUT_CODE,
111
+ /** The input, or one of its lines, is longer than a JavaScript string can hold. The import stops. */
112
+ TOO_LARGE: TOO_LARGE_CODE,
113
+ /** A byte order mark, the encoding option and the declared encoding disagree. */
114
+ ENCODING_CONFLICT: ENCODING_CONFLICT_CODE,
115
+ /** A control character or a stray U+FEFF in the text, or an ignored trailing Ctrl-Z. */
116
+ CONTROL_CHARACTER: CONTROL_CHARACTER_CODE,
117
+ /** The input is an HTML page, a PDF, compressed or zip data, or an image. The import stops. */
118
+ FOREIGN_FORMAT: FOREIGN_FORMAT_CODE,
119
+ /** Warnings of one code beyond the number a report keeps, counted in one warning. */
120
+ ISSUES_SUPPRESSED: ISSUES_SUPPRESSED_CODE
121
+ });
122
+ function plural(n) {
123
+ return n === 1 ? "" : "s";
124
+ }
125
+ function agree(n, one, many) {
126
+ return n === 1 ? one : many;
127
+ }
128
+ function elementCount(nodes, edges) {
129
+ const parts = [];
130
+ if (nodes > 0 || edges === 0) {
131
+ parts.push(`${nodes} node${plural(nodes)}`);
132
+ }
133
+ if (edges > 0) {
134
+ parts.push(`${edges} edge${plural(edges)}`);
135
+ }
136
+ return parts.join(" and ");
137
+ }
138
+ function withArticle(word) {
139
+ return `${/^[aeiou]/i.test(word) ? "an" : "a"} ${word}`;
140
+ }
141
+ const TIME_TEXT_ROLE = "timeText";
142
+ const TIME_TEXT_SUFFIX = ".text";
143
+ const DATE_TIME$1 = /^(-?[0-9]{4,})-([0-9]{2})-([0-9]{2})(?:[T ]([0-9]{2}):([0-9]{2})(?::([0-9]{2})(?:\.([0-9]{1,9}))?)?)?(Z|z|[+-][0-9]{2}(?::?[0-9]{2})?)?$/;
144
+ const TIME$1 = /^([0-9]{2}):([0-9]{2})(?::([0-9]{2})(?:\.([0-9]{1,9}))?)?(Z|z|[+-][0-9]{2}(?::?[0-9]{2})?)?$/;
145
+ const NUMERIC = /^[+-]?([0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?$/;
146
+ const MS_PER_MINUTE = 6e4;
147
+ const MS_PER_DAY = 864e5;
148
+ function parseTemporal(text, kind) {
149
+ let value;
150
+ switch (kind) {
151
+ case "date":
152
+ case "dateTime":
153
+ case "localDateTime":
154
+ value = parseDateTime(text, kind);
155
+ break;
156
+ case "time":
157
+ case "localTime":
158
+ value = parseTime(text, kind);
159
+ break;
160
+ default: {
161
+ const name = kind;
162
+ throw new GraphFormatError("E_COLUMN_TYPE", `unknown temporal kind ${name}`, { kind: name });
163
+ }
164
+ }
165
+ const canonical = formatTemporal(value, kind);
166
+ return { value, text: canonical === text ? null : text };
167
+ }
168
+ function parseTimeText(text, timeFormat) {
169
+ const trimmed = text.trim();
170
+ switch (timeFormat) {
171
+ case "integer":
172
+ case "double":
173
+ return parseNumericTime(trimmed);
174
+ case "date":
175
+ return parseTemporal(trimmed, "date");
176
+ case "dateTime":
177
+ return parseTemporal(trimmed, "dateTime");
178
+ case null:
179
+ return NUMERIC.test(trimmed) ? parseNumericTime(trimmed) : parseTemporal(trimmed, "dateTime");
180
+ default: {
181
+ const name = timeFormat;
182
+ throw new GraphFormatError("E_COLUMN_TYPE", `unknown timeformat ${name}`, { timeFormat: name });
183
+ }
184
+ }
185
+ }
186
+ function formatTemporal(value, kind) {
187
+ switch (kind) {
188
+ case "date": {
189
+ const d = new Date(value);
190
+ return `${year(d)}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}`;
191
+ }
192
+ case "dateTime":
193
+ case "localDateTime": {
194
+ const d = new Date(value);
195
+ const date = `${year(d)}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}`;
196
+ const time = clock(d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
197
+ return kind === "dateTime" ? `${date}T${time}Z` : `${date}T${time}`;
198
+ }
199
+ case "time":
200
+ case "localTime": {
201
+ const ms = (value % MS_PER_DAY + MS_PER_DAY) % MS_PER_DAY;
202
+ const h = Math.floor(ms / 36e5);
203
+ const m = Math.floor(ms % 36e5 / MS_PER_MINUTE);
204
+ const s = Math.floor(ms % MS_PER_MINUTE / 1e3);
205
+ const text = clock(h, m, s, ms % 1e3);
206
+ return kind === "time" ? `${text}Z` : text;
207
+ }
208
+ default: {
209
+ const name = kind;
210
+ throw new GraphFormatError("E_COLUMN_TYPE", `unknown temporal kind ${name}`, { kind: name });
211
+ }
212
+ }
213
+ }
214
+ function formatTimeValue(value, timeFormat) {
215
+ switch (timeFormat) {
216
+ case "date":
217
+ return formatTemporal(value, "date");
218
+ case "dateTime":
219
+ return formatTemporal(value, "dateTime");
220
+ case "integer":
221
+ case "double":
222
+ case null:
223
+ return String(value);
224
+ default: {
225
+ const name = timeFormat;
226
+ throw new GraphFormatError("E_COLUMN_TYPE", `unknown timeformat ${name}`, { timeFormat: name });
227
+ }
228
+ }
229
+ }
230
+ function timeTextCompanion(column) {
231
+ return {
232
+ name: column + TIME_TEXT_SUFFIX,
233
+ dtype: "string",
234
+ role: TIME_TEXT_ROLE,
235
+ nullable: true,
236
+ extra: { for: column }
237
+ };
238
+ }
239
+ function parseNumericTime(text) {
240
+ if (!NUMERIC.test(text)) {
241
+ throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is not a numeric time`, { value: text });
242
+ }
243
+ const value = Number(text);
244
+ return { value, text: String(value) === text ? null : text };
245
+ }
246
+ function parseDateTime(text, kind) {
247
+ const m = DATE_TIME$1.exec(text);
248
+ if (m === null) {
249
+ throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is not an ISO-8601 ${kind}`, { value: text, kind });
250
+ }
251
+ const y = Number(m[1]);
252
+ const month = Number(m[2]);
253
+ const day = Number(m[3]);
254
+ const hour = m[4] === void 0 ? 0 : Number(m[4]);
255
+ const minute = m[5] === void 0 ? 0 : Number(m[5]);
256
+ const second = m[6] === void 0 ? 0 : Number(m[6]);
257
+ const ms = m[7] === void 0 ? 0 : fractionMs(m[7]);
258
+ if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 24 || minute > 59 || second > 60) {
259
+ throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is out of range for a ${kind}`, { value: text, kind });
260
+ }
261
+ const d = /* @__PURE__ */ new Date(0);
262
+ d.setUTCFullYear(y, month - 1, day);
263
+ d.setUTCHours(hour, minute, second, ms);
264
+ if (d.getUTCDate() !== day && hour !== 24) {
265
+ throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is not a calendar date`, { value: text, kind });
266
+ }
267
+ const offset = m[8] === void 0 ? 0 : offsetMinutes(m[8]);
268
+ return d.getTime() - offset * MS_PER_MINUTE;
269
+ }
270
+ function parseTime(text, kind) {
271
+ const m = TIME$1.exec(text);
272
+ if (m === null) {
273
+ throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is not an ISO-8601 ${kind}`, { value: text, kind });
274
+ }
275
+ const hour = Number(m[1]);
276
+ const minute = Number(m[2]);
277
+ const second = m[3] === void 0 ? 0 : Number(m[3]);
278
+ const ms = m[4] === void 0 ? 0 : fractionMs(m[4]);
279
+ if (hour > 24 || minute > 59 || second > 60) {
280
+ throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is out of range for a ${kind}`, { value: text, kind });
281
+ }
282
+ const local = ((hour * 60 + minute) * 60 + second) * 1e3 + ms;
283
+ const offset = m[5] === void 0 ? 0 : offsetMinutes(m[5]);
284
+ const utc = local - offset * MS_PER_MINUTE;
285
+ return (utc % MS_PER_DAY + MS_PER_DAY) % MS_PER_DAY;
286
+ }
287
+ function fractionMs(digits) {
288
+ return Math.floor(Number(`0.${digits}`) * 1e3);
289
+ }
290
+ function offsetMinutes(zone) {
291
+ if (zone === "Z" || zone === "z") {
292
+ return 0;
293
+ }
294
+ const sign = zone.startsWith("-") ? -1 : 1;
295
+ const digits = zone.slice(1).replace(":", "");
296
+ const hours = Number(digits.slice(0, 2));
297
+ const minutes = digits.length > 2 ? Number(digits.slice(2, 4)) : 0;
298
+ return sign * (hours * 60 + minutes);
299
+ }
300
+ function pad2(n) {
301
+ return n < 10 ? `0${n}` : String(n);
302
+ }
303
+ function year(d) {
304
+ const y = d.getUTCFullYear();
305
+ const abs = String(Math.abs(y)).padStart(4, "0");
306
+ return y < 0 ? `-${abs}` : abs;
307
+ }
308
+ function clock(h, m, s, ms) {
309
+ const base = `${pad2(h)}:${pad2(m)}:${pad2(s)}`;
310
+ return ms === 0 ? base : `${base}.${String(ms).padStart(3, "0")}`;
311
+ }
312
+ const BOOLEAN = { dtype: "bool", kind: "boolean" };
313
+ const INTEGER = { dtype: "i32", kind: "integer" };
314
+ const LONG = { dtype: "f64", kind: "long", precision: true };
315
+ const FLOAT = { dtype: "f32", kind: "float" };
316
+ const DOUBLE = { dtype: "f64", kind: "double" };
317
+ const STRING = { dtype: "string", kind: "string" };
318
+ const DATE = { dtype: "f64", kind: "temporal", temporal: "date" };
319
+ const DATE_TIME = { dtype: "f64", kind: "temporal", temporal: "dateTime" };
320
+ const LOCAL_DATE_TIME = { dtype: "f64", kind: "temporal", temporal: "localDateTime" };
321
+ const TIME = { dtype: "f64", kind: "temporal", temporal: "time" };
322
+ const LOCAL_TIME = { dtype: "f64", kind: "temporal", temporal: "localTime" };
323
+ const DURATION = { dtype: "string", kind: "duration" };
324
+ const POINT = { dtype: "json", kind: "point" };
325
+ const RECORD = { dtype: "json", kind: "json" };
326
+ const GEXF_SCALARS = {
327
+ integer: INTEGER,
328
+ long: LONG,
329
+ double: DOUBLE,
330
+ float: FLOAT,
331
+ boolean: BOOLEAN,
332
+ string: STRING,
333
+ anyuri: STRING,
334
+ char: STRING,
335
+ byte: INTEGER,
336
+ short: INTEGER,
337
+ bigdecimal: STRING,
338
+ biginteger: STRING,
339
+ date: DATE,
340
+ datetime: DATE_TIME
341
+ };
342
+ const GRAPHML_SCALARS = {
343
+ boolean: BOOLEAN,
344
+ int: INTEGER,
345
+ long: LONG,
346
+ float: FLOAT,
347
+ double: DOUBLE,
348
+ string: STRING
349
+ };
350
+ const GML_SCALARS = {
351
+ int: INTEGER,
352
+ real: DOUBLE,
353
+ string: STRING,
354
+ record: RECORD
355
+ };
356
+ const NEO4J_SCALARS = {
357
+ int: INTEGER,
358
+ integer: LONG,
359
+ long: LONG,
360
+ float: FLOAT,
361
+ double: DOUBLE,
362
+ boolean: BOOLEAN,
363
+ byte: INTEGER,
364
+ short: INTEGER,
365
+ char: STRING,
366
+ string: STRING,
367
+ point: POINT,
368
+ date: DATE,
369
+ localtime: LOCAL_TIME,
370
+ time: TIME,
371
+ localdatetime: LOCAL_DATE_TIME,
372
+ datetime: DATE_TIME,
373
+ duration: DURATION
374
+ };
375
+ const TABLES = {
376
+ gexf: GEXF_SCALARS,
377
+ graphml: GRAPHML_SCALARS,
378
+ gml: GML_SCALARS,
379
+ neo4j: NEO4J_SCALARS
380
+ };
381
+ const INTEGER_TEXT$1 = /^[+-]?[0-9]+$/;
382
+ const DECIMAL_TEXT = /^[+-]?([0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?$/;
383
+ const I32_MIN = -2147483648;
384
+ const I32_MAX = 2147483647;
385
+ function mapDeclaredType(format, type, long) {
386
+ const table = TABLES[format];
387
+ let key = type.trim().toLowerCase();
388
+ let list2 = false;
389
+ if (format === "gexf" && key.startsWith("list") && key.length > 4) {
390
+ list2 = true;
391
+ key = key.slice(4);
392
+ } else if (format === "neo4j" && key.endsWith("[]")) {
393
+ list2 = true;
394
+ key = key.slice(0, -2);
395
+ } else if (format === "gml" && key === "list") {
396
+ return {
397
+ declared: type,
398
+ dtype: "list",
399
+ itemDtype: "json",
400
+ kind: "json",
401
+ list: true,
402
+ temporal: null,
403
+ precision: false
404
+ };
405
+ }
406
+ let entry = table[key];
407
+ if (entry === void 0) {
408
+ return null;
409
+ }
410
+ if (entry.kind === "long" && long === "string") {
411
+ entry = STRING;
412
+ }
413
+ return {
414
+ declared: type,
415
+ dtype: list2 ? "list" : entry.dtype,
416
+ itemDtype: list2 ? entry.dtype : null,
417
+ kind: entry.kind,
418
+ list: list2,
419
+ temporal: entry.temporal ?? null,
420
+ precision: entry.precision ?? false
421
+ };
422
+ }
423
+ function stringSpec(declared) {
424
+ return {
425
+ declared: declared ?? "",
426
+ dtype: "string",
427
+ itemDtype: null,
428
+ kind: "string",
429
+ list: false,
430
+ temporal: null,
431
+ precision: false
432
+ };
433
+ }
434
+ function parseScalarText(text, kind, temporal = null) {
435
+ switch (kind) {
436
+ case "boolean": {
437
+ const value = parseBooleanText(text);
438
+ if (value === null) {
439
+ throw typeError(text, kind);
440
+ }
441
+ return value;
442
+ }
443
+ case "integer": {
444
+ const trimmed = text.trim();
445
+ if (!INTEGER_TEXT$1.test(trimmed)) {
446
+ throw typeError(text, kind);
447
+ }
448
+ const value = Number(trimmed);
449
+ if (value < I32_MIN || value > I32_MAX) {
450
+ throw new GraphFormatError("E_COLUMN_TYPE", `"${trimmed}" is outside the 32-bit integer range`, {
451
+ value: trimmed,
452
+ kind
453
+ });
454
+ }
455
+ return value;
456
+ }
457
+ case "long": {
458
+ const trimmed = text.trim();
459
+ if (!INTEGER_TEXT$1.test(trimmed)) {
460
+ throw typeError(text, kind);
461
+ }
462
+ return Number(trimmed);
463
+ }
464
+ case "float":
465
+ case "double":
466
+ return parseDecimalText(text, kind);
467
+ case "string":
468
+ case "duration":
469
+ return text;
470
+ case "temporal": {
471
+ if (temporal === null) {
472
+ throw new GraphFormatError("E_COLUMN_TYPE", "a temporal value needs its temporal kind", { kind });
473
+ }
474
+ return parseTemporal(text.trim(), temporal).value;
475
+ }
476
+ case "point":
477
+ return parsePointText(text);
478
+ case "json":
479
+ return parseJsonText(text);
480
+ default: {
481
+ const name = kind;
482
+ throw new GraphFormatError("E_COLUMN_TYPE", `unknown value kind ${name}`, { kind: name });
483
+ }
484
+ }
485
+ }
486
+ function parseBooleanText(text) {
487
+ switch (text.trim().toLowerCase()) {
488
+ case "true":
489
+ case "1":
490
+ return true;
491
+ case "false":
492
+ case "0":
493
+ return false;
494
+ default:
495
+ return null;
496
+ }
497
+ }
498
+ function parseDecimalText(text, kind = "double") {
499
+ const trimmed = text.trim();
500
+ if (DECIMAL_TEXT.test(trimmed)) {
501
+ return Number(trimmed);
502
+ }
503
+ switch (trimmed) {
504
+ case "INF":
505
+ case "+INF":
506
+ case "Infinity":
507
+ case "+Infinity":
508
+ return Infinity;
509
+ case "-INF":
510
+ case "-Infinity":
511
+ return -Infinity;
512
+ case "NaN":
513
+ return NaN;
514
+ default:
515
+ throw typeError(text, kind);
516
+ }
517
+ }
518
+ function overflowsToInfinity(text) {
519
+ const trimmed = text.trim();
520
+ return /^[+-]?[0-9.]/.test(trimmed) && Number(trimmed) === (trimmed.startsWith("-") ? -Infinity : Infinity);
521
+ }
522
+ function parsePointText(text) {
523
+ const trimmed = text.trim();
524
+ if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
525
+ throw typeError(text, "point");
526
+ }
527
+ const out = {};
528
+ const inner = trimmed.slice(1, -1).trim();
529
+ if (inner.length === 0) {
530
+ return out;
531
+ }
532
+ for (const part of inner.split(",")) {
533
+ const colon = part.indexOf(":");
534
+ if (colon < 0) {
535
+ throw typeError(text, "point");
536
+ }
537
+ const key = part.slice(0, colon).trim().replace(/^["']|["']$/g, "");
538
+ const raw = part.slice(colon + 1).trim();
539
+ if (key.length === 0) {
540
+ throw typeError(text, "point");
541
+ }
542
+ if (DECIMAL_TEXT.test(raw)) {
543
+ out[key] = Number(raw);
544
+ } else if (raw.startsWith("'") && raw.endsWith("'") || raw.startsWith('"') && raw.endsWith('"')) {
545
+ out[key] = raw.slice(1, -1);
546
+ } else {
547
+ throw typeError(text, "point");
548
+ }
549
+ }
550
+ return out;
551
+ }
552
+ function parseJsonText(text) {
553
+ try {
554
+ return JSON.parse(text);
555
+ } catch {
556
+ throw typeError(text, "json");
557
+ }
558
+ }
559
+ function typeError(text, kind) {
560
+ const shown = text.length > 40 ? `${text.slice(0, 40)}...` : text;
561
+ return new GraphFormatError("E_COLUMN_TYPE", `"${shown}" is not ${withArticle(kind)}`, { value: text, kind });
562
+ }
563
+ function splitListText(text, syntax) {
564
+ const trimmed = text.trim();
565
+ if (trimmed.length === 0) {
566
+ return [];
567
+ }
568
+ switch (syntax) {
569
+ case "gexf": {
570
+ if (isBracketed(trimmed)) {
571
+ return splitBracketed(trimmed);
572
+ }
573
+ const separator = firstSeparator(trimmed, ["|", ",", ";"]);
574
+ return separator === null ? [trimmed] : splitOn(trimmed, separator);
575
+ }
576
+ case "brackets":
577
+ return isBracketed(trimmed) ? splitBracketed(trimmed) : [trimmed];
578
+ case "pipe":
579
+ return splitOn(trimmed, "|");
580
+ case "comma":
581
+ return splitOn(trimmed, ",");
582
+ case "semicolon":
583
+ return splitOn(trimmed, ";");
584
+ default: {
585
+ const name = syntax;
586
+ throw new GraphFormatError("E_UNSUPPORTED", `unknown list syntax ${name}`, {
587
+ option: "listSyntax",
588
+ found: name
589
+ });
590
+ }
591
+ }
592
+ }
593
+ function joinListText(items, syntax) {
594
+ switch (syntax) {
595
+ case "gexf":
596
+ case "brackets":
597
+ return `[${items.map(quoteBracketItem).join(", ")}]`;
598
+ case "pipe":
599
+ return items.join("|");
600
+ case "comma":
601
+ return items.join(",");
602
+ case "semicolon":
603
+ return items.join(";");
604
+ default: {
605
+ const name = syntax;
606
+ throw new GraphFormatError("E_UNSUPPORTED", `unknown list syntax ${name}`, {
607
+ option: "listSyntax",
608
+ found: name
609
+ });
610
+ }
611
+ }
612
+ }
613
+ function isBracketed(text) {
614
+ return text.length >= 2 && text.startsWith("[") && text.endsWith("]");
615
+ }
616
+ function firstSeparator(text, candidates) {
617
+ for (const candidate of candidates) {
618
+ if (text.includes(candidate)) {
619
+ return candidate;
620
+ }
621
+ }
622
+ return null;
623
+ }
624
+ function splitOn(text, separator) {
625
+ return text.split(separator).map((item) => item.trim());
626
+ }
627
+ function splitBracketed(text) {
628
+ const inner = text.slice(1, -1);
629
+ const items = [];
630
+ const n = inner.length;
631
+ if (inner.trim().length === 0) {
632
+ return items;
633
+ }
634
+ let i = 0;
635
+ for (; ; ) {
636
+ while (i < n && isSpace(inner.charCodeAt(i))) {
637
+ i++;
638
+ }
639
+ let item = "";
640
+ if (i < n && (inner[i] === '"' || inner[i] === "'")) {
641
+ const quote = inner[i];
642
+ i++;
643
+ while (i < n) {
644
+ if (inner[i] === quote) {
645
+ if (inner[i + 1] === quote) {
646
+ item += quote;
647
+ i += 2;
648
+ continue;
649
+ }
650
+ i++;
651
+ break;
652
+ }
653
+ item += inner[i];
654
+ i++;
655
+ }
656
+ }
657
+ let end = inner.indexOf(",", i);
658
+ if (end < 0) {
659
+ end = n;
660
+ }
661
+ item += inner.slice(i, end).trim();
662
+ items.push(item);
663
+ i = end;
664
+ if (i >= n) {
665
+ return items;
666
+ }
667
+ i++;
668
+ if (inner.slice(i).trim().length === 0) {
669
+ items.push("");
670
+ return items;
671
+ }
672
+ }
673
+ }
674
+ function isSpace(c) {
675
+ return c === 32 || c === 9 || c === 13 || c === 10;
676
+ }
677
+ function quoteBracketItem(item) {
678
+ if (item.length === 0 || /[,[\]"']/.test(item) || item !== item.trim()) {
679
+ return `"${item.replace(/"/g, '""')}"`;
680
+ }
681
+ return item;
682
+ }
683
+ const UNKNOWN_TYPE_CODE = UNKNOWN_ATTR_TYPE_CODE;
684
+ const RENAMED_CODE = COLUMN_RENAMED_CODE;
685
+ const DICT_SAMPLE_ROWS = 1024;
686
+ function declareAttribute(input) {
687
+ const issues = [];
688
+ const listSyntax = input.listSyntax ?? "gexf";
689
+ let spec;
690
+ if (input.type === null) {
691
+ spec = stringSpec(null);
692
+ } else {
693
+ const mapped = mapDeclaredType(input.format, input.type, input.long);
694
+ if (mapped === null) {
695
+ spec = stringSpec(input.type);
696
+ issues.push({
697
+ category: "unsupported",
698
+ code: UNKNOWN_TYPE_CODE,
699
+ message: `${input.format} type "${input.type}" is not supported; values kept as text`
700
+ });
701
+ } else {
702
+ spec = mapped;
703
+ }
704
+ }
705
+ const { name, renamed } = resolveName(input);
706
+ if (renamed) {
707
+ issues.push({
708
+ category: "coercion",
709
+ code: RENAMED_CODE,
710
+ message: `attribute "${input.title ?? input.id ?? ""}" renamed to "${name}": the name was taken`
711
+ });
712
+ }
713
+ const decl = {
714
+ name,
715
+ dtype: spec.dtype,
716
+ nullable: true,
717
+ origin: {
718
+ format: input.format,
719
+ id: input.id,
720
+ title: input.title !== null && input.title !== name ? input.title : null,
721
+ type: input.type,
722
+ namespace: input.namespace ?? null
723
+ }
724
+ };
725
+ if (spec.list) {
726
+ decl.itemDtype = spec.itemDtype ?? "string";
727
+ }
728
+ if (input.role !== void 0 && input.role !== null) {
729
+ decl.role = input.role;
730
+ }
731
+ if (input.dynamic === true) {
732
+ decl.dynamic = true;
733
+ }
734
+ const optionsText = input.optionsText ?? null;
735
+ if (optionsText !== null) {
736
+ try {
737
+ const options = splitListText(optionsText, listSyntax).map((item) => parseItem(item, spec));
738
+ decl.options = options;
739
+ if (spec.dtype === "string" && !spec.list && options.every((o) => typeof o === "string")) {
740
+ decl.dtype = "dict";
741
+ spec = { ...spec, dtype: "dict" };
742
+ }
743
+ } catch (err) {
744
+ issues.push({
745
+ category: "validation-error",
746
+ code: BAD_OPTIONS_CODE,
747
+ message: `options "${optionsText}" of attribute "${name}" do not parse as ${spec.declared}: ${messageOf$1(err)}`
748
+ });
749
+ }
750
+ }
751
+ const defaultText = input.defaultText ?? null;
752
+ if (defaultText !== null) {
753
+ try {
754
+ decl.default = parseDeclaredValue(defaultText, spec, listSyntax);
755
+ } catch (err) {
756
+ issues.push({
757
+ category: "validation-error",
758
+ code: BAD_DEFAULT_CODE,
759
+ message: `default "${defaultText}" of attribute "${name}" does not parse as ${spec.declared}: ${messageOf$1(err)}`
760
+ });
761
+ }
762
+ }
763
+ const companion = spec.temporal !== null && !spec.list ? timeTextCompanion(name) : null;
764
+ return { decl, spec, listSyntax, companion, renamed, issues };
765
+ }
766
+ function parseDeclaredValue(text, spec, listSyntax) {
767
+ if (spec.list) {
768
+ return splitListText(text, listSyntax).map((item) => parseItem(item, spec));
769
+ }
770
+ return parseItem(text, spec);
771
+ }
772
+ function parseDeclaredTemporal(text, spec) {
773
+ if (spec.temporal === null || spec.list) {
774
+ throw new GraphFormatError("E_COLUMN_TYPE", `"${spec.declared}" is not a scalar temporal type`, {
775
+ declared: spec.declared
776
+ });
777
+ }
778
+ return parseTemporal(text.trim(), spec.temporal);
779
+ }
780
+ const INTEGER_TEXT = /^[+-]?[0-9]+$/;
781
+ function losesPrecision(spec, text) {
782
+ if (!spec.precision) {
783
+ return false;
784
+ }
785
+ const trimmed = text.trim();
786
+ if (!INTEGER_TEXT.test(trimmed)) {
787
+ return false;
788
+ }
789
+ const n = Number(trimmed);
790
+ return !Number.isFinite(n) || BigInt(trimmed) !== BigInt(n);
791
+ }
792
+ function declareOn(sink, domain, decl) {
793
+ return domain === "node" ? sink.declareNodeColumn(decl) : sink.declareEdgeColumn(decl);
794
+ }
795
+ function declareResolved(sink, domain, decl, report, where) {
796
+ let current = decl;
797
+ let renamed = false;
798
+ let roleDropped = false;
799
+ for (; ; ) {
800
+ try {
801
+ return { handle: declareOn(sink, domain, current), decl: current, renamed, roleDropped };
802
+ } catch (err) {
803
+ if (!(err instanceof GraphFormatError)) {
804
+ throw err;
805
+ }
806
+ if (err.code === "E_COLUMN_EXISTS" && !renamed) {
807
+ const taken = takenIn(sink, domain);
808
+ const id = current.origin?.id ?? null;
809
+ const name = uniqueColumnName(current.name, id, taken);
810
+ report.warning(
811
+ "coercion",
812
+ COLUMN_RENAMED_CODE,
813
+ `${domain} column "${current.name}" renamed to "${name}": the sink already holds that name with another shape`,
814
+ { ...where, element: where?.element ?? current.name }
815
+ );
816
+ current = { ...current, name };
817
+ renamed = true;
818
+ continue;
819
+ }
820
+ if (err.code === "E_DUPLICATE_ROLE" && current.role !== void 0 && !roleDropped) {
821
+ const holder = typeof err.details.holder === "string" ? err.details.holder : "another column";
822
+ report.warning(
823
+ "coercion",
824
+ ROLE_TAKEN_CODE,
825
+ `${domain} column "${current.name}" loses the ${current.role} role: "${holder}" already holds it`,
826
+ { ...where, element: where?.element ?? current.name }
827
+ );
828
+ const { role: _role, ...withoutRole } = current;
829
+ current = withoutRole;
830
+ roleDropped = true;
831
+ continue;
832
+ }
833
+ throw err;
834
+ }
835
+ }
836
+ }
837
+ function declareCompanion(sink, domain, companion, report) {
838
+ try {
839
+ return declareOn(sink, domain, companion);
840
+ } catch (err) {
841
+ if (err instanceof GraphFormatError && err.code === "E_DUPLICATE_ROLE") {
842
+ report?.warnOnce(
843
+ "coercion",
844
+ ROLE_TAKEN_CODE,
845
+ `${domain} column "${companion.name}" is declared without the timeText role: another companion holds it (exporters use extra.for)`,
846
+ { element: companion.name }
847
+ );
848
+ const { role: _role, ...withoutRole } = companion;
849
+ return declareOn(sink, domain, withoutRole);
850
+ }
851
+ throw err;
852
+ }
853
+ }
854
+ function takenIn(sink, domain) {
855
+ return (name) => (domain === "node" ? sink.nodeColumn(name) : sink.edgeColumn(name)) !== INVALID_INDEX;
856
+ }
857
+ function uniqueColumnName(name, id, taken) {
858
+ if (!taken(name)) {
859
+ return name;
860
+ }
861
+ const base = id === null ? name : `${name}#${id}`;
862
+ if (id !== null && !taken(base)) {
863
+ return base;
864
+ }
865
+ for (let n = 2; ; n++) {
866
+ const candidate = `${base}#${n}`;
867
+ if (!taken(candidate)) {
868
+ return candidate;
869
+ }
870
+ }
871
+ }
872
+ class DictHeuristic {
873
+ /**
874
+ * Create a heuristic.
875
+ * @param sampleRows - rows observed before deciding; DICT_SAMPLE_ROWS by default
876
+ */
877
+ constructor(sampleRows = DICT_SAMPLE_ROWS) {
878
+ this.distinct = /* @__PURE__ */ new Set();
879
+ this.rowsSeen = 0;
880
+ this.sampleRows = sampleRows;
881
+ }
882
+ /**
883
+ * Rows observed so far.
884
+ * @returns the count
885
+ */
886
+ get rows() {
887
+ return this.rowsSeen;
888
+ }
889
+ /**
890
+ * Distinct values observed so far.
891
+ * @returns the count
892
+ */
893
+ get distinctCount() {
894
+ return this.distinct.size;
895
+ }
896
+ /**
897
+ * Whether the sample is full.
898
+ * @returns true once sampleRows values were observed
899
+ */
900
+ get decided() {
901
+ return this.rowsSeen >= this.sampleRows;
902
+ }
903
+ /**
904
+ * Observe one value.
905
+ * @param value - the value text
906
+ * @returns true when this observation completed the sample
907
+ */
908
+ observe(value) {
909
+ this.rowsSeen++;
910
+ if (this.distinct.size < this.rowsSeen) {
911
+ this.distinct.add(value);
912
+ }
913
+ return this.rowsSeen === this.sampleRows;
914
+ }
915
+ /**
916
+ * The dtype the sample suggests: dict when the distinct count is below rows / 2 (and at least
917
+ * one row was seen), string otherwise. Valid before the sample is full (end of input).
918
+ * @returns "dict" or "string"
919
+ */
920
+ decide() {
921
+ return this.rowsSeen > 0 && this.distinct.size * 2 < this.rowsSeen ? "dict" : "string";
922
+ }
923
+ }
924
+ function resolveName(input) {
925
+ const preferred = input.title !== null && input.title.length > 0 ? input.title : input.id;
926
+ if (preferred === null || preferred.length === 0) {
927
+ throw new GraphFormatError("E_COLUMN_TYPE", "an attribute declaration needs a title or an id", {
928
+ field: "name",
929
+ format: input.format
930
+ });
931
+ }
932
+ if (input.taken === void 0) {
933
+ return { name: preferred, renamed: false };
934
+ }
935
+ const name = uniqueColumnName(preferred, input.id, input.taken);
936
+ return { name, renamed: name !== preferred };
937
+ }
938
+ function parseItem(text, spec) {
939
+ return parseScalarText(text, spec.kind, spec.temporal);
940
+ }
941
+ function messageOf$1(err) {
942
+ return err instanceof Error ? err.message : String(err);
943
+ }
944
+ const DIRECTED_COLUMN = "graphty.directed";
945
+ const PAIR_COLUMN = "graphty.pair";
946
+ const MUTUAL_COLUMN = "graphty.mutual";
947
+ const DIRECTED_DECL = { name: DIRECTED_COLUMN, dtype: "bool", role: "directed" };
948
+ const PAIR_DECL = { name: PAIR_COLUMN, dtype: "u32", role: "pair", refersTo: "edge" };
949
+ const MUTUAL_DECL = { name: MUTUAL_COLUMN, dtype: "bool", role: "mutual" };
950
+ class DirectionResolver {
951
+ /**
952
+ * Create a resolver.
953
+ * @param sink - the sink edges are pushed into
954
+ * @param report - the report issues are recorded in
955
+ * @param policy - the resolved onMixedDirection option
956
+ */
957
+ constructor(sink, report, policy) {
958
+ this.directedHandle = INVALID_INDEX;
959
+ this.pairHandle = INVALID_INDEX;
960
+ this.mutualHandle = INVALID_INDEX;
961
+ this.firstEdge = -1;
962
+ this.nextEdge = -1;
963
+ this.forcedCount = 0;
964
+ this.headerSet = false;
965
+ this.mirrorOfLast = INVALID_INDEX;
966
+ this.sink = sink;
967
+ this.report = report;
968
+ this.policy = policy;
969
+ }
970
+ /**
971
+ * The sink's current direction.
972
+ * @returns true when directed
973
+ */
974
+ get directed() {
975
+ return this.sink.directed;
976
+ }
977
+ /**
978
+ * Whether the graph holds undirected edges stored as two edges.
979
+ * @returns true once the first such edge was added
980
+ */
981
+ get expanded() {
982
+ return this.pairHandle !== INVALID_INDEX;
983
+ }
984
+ /**
985
+ * Set the graph's direction before the first edge: the direction the file declares, or the
986
+ * `defaultDirected` option for a file that declares none. Under `onMixedDirection` "directed" or
987
+ * "undirected" that direction is used instead, with a warning when it differs. When the sink
988
+ * cannot change direction (a caller's builder that already holds edges or was locked), the
989
+ * sink's direction stands and a warning is recorded.
990
+ * @param headerDirected - the direction the file declares (or the default)
991
+ * @param where - the line of the header, when known
992
+ */
993
+ setHeader(headerDirected, where) {
994
+ this.headerSet = true;
995
+ let wanted = headerDirected;
996
+ if (this.policy === "directed" || this.policy === "undirected") {
997
+ wanted = this.policy === "directed";
998
+ if (wanted !== headerDirected) {
999
+ this.report.warnOnce(
1000
+ "coercion",
1001
+ DIRECTION_FORCED_CODE,
1002
+ `the file declares ${direction(headerDirected)} edges; read as ${direction(wanted)} per onMixedDirection`,
1003
+ { line: where?.line ?? null },
1004
+ `${DIRECTION_FORCED_CODE}:${direction(headerDirected)}`
1005
+ );
1006
+ }
1007
+ }
1008
+ const { sink } = this;
1009
+ if (sink.directed === wanted) {
1010
+ this.adoptExisting();
1011
+ return;
1012
+ }
1013
+ try {
1014
+ if (wanted && sink.edgeCount > 0 && !sink.directedLocked) {
1015
+ const before = sink.edgeCount;
1016
+ sink.setDirected(true, { expand: true });
1017
+ this.adoptExpansionColumns();
1018
+ this.report.counts.expandedMixed += before;
1019
+ } else {
1020
+ sink.setDirected(wanted);
1021
+ }
1022
+ } catch (err) {
1023
+ if (!(err instanceof GraphFormatError) || err.code !== "E_DIRECTED") {
1024
+ throw err;
1025
+ }
1026
+ this.report.warning(
1027
+ "coercion",
1028
+ DIRECTION_REFUSED_CODE,
1029
+ `the file is ${direction(wanted)} but the sink is ${direction(sink.directed)} (${reasonOf(err)}); read as ${direction(sink.directed)}`,
1030
+ { line: where?.line ?? null }
1031
+ );
1032
+ }
1033
+ this.adoptExisting();
1034
+ }
1035
+ /**
1036
+ * Pick up reserved columns a caller's sink already holds (an earlier expansion), so every edge
1037
+ * pushed from now on gets its graphty.directed value.
1038
+ */
1039
+ adoptExisting() {
1040
+ if (this.pairHandle === INVALID_INDEX && this.sink.edgeColumn(PAIR_COLUMN) !== INVALID_INDEX) {
1041
+ this.adoptExpansionColumns();
1042
+ }
1043
+ }
1044
+ /**
1045
+ * The second edge of the edge the last addEdge() call added, when that edge was stored as two;
1046
+ * otherwise INVALID_INDEX (4294967295). An edge attribute or weight you set after addEdge()
1047
+ * belongs on both: set it on the index addEdge() returned and, when this is not INVALID_INDEX,
1048
+ * on this index too.
1049
+ * @returns the second edge's index, or INVALID_INDEX
1050
+ */
1051
+ get lastMirror() {
1052
+ return this.mirrorOfLast;
1053
+ }
1054
+ /**
1055
+ * Add one edge. An edge with the graph's direction is added as it is; one with the other
1056
+ * direction is stored as two edges, given the graph's direction, or refused, as
1057
+ * `onMixedDirection` says. When it is stored as two, the return value is the first and
1058
+ * `lastMirror` the second.
1059
+ * @param source - the source id
1060
+ * @param target - the target id
1061
+ * @param kind - the edge's direction in the file
1062
+ * @param weight - the weight, or undefined when the file gives none
1063
+ * @param where - the line and element, for issues
1064
+ * @returns the index of the edge added (the first one, when it was stored as two)
1065
+ */
1066
+ addEdge(source, target, kind, weight, where) {
1067
+ if (!this.headerSet) {
1068
+ throw new GraphFormatError("E_DIRECTED", "DirectionResolver.setHeader() must run before the first edge", {
1069
+ reason: "header not set"
1070
+ });
1071
+ }
1072
+ const { sink } = this;
1073
+ this.mirrorOfLast = INVALID_INDEX;
1074
+ const edgeDirected = kind !== "undirected";
1075
+ if (edgeDirected === sink.directed && kind !== "mutual") {
1076
+ const e = sink.addEdge(source, target, weight);
1077
+ this.track(e);
1078
+ if (this.directedHandle !== INVALID_INDEX) {
1079
+ sink.setEdgeValue(this.directedHandle, e, edgeDirected);
1080
+ }
1081
+ return e;
1082
+ }
1083
+ switch (this.policy) {
1084
+ case "directed":
1085
+ case "undirected": {
1086
+ this.forcedCount++;
1087
+ this.report.warnOnce(
1088
+ "coercion",
1089
+ DIRECTION_FORCED_CODE,
1090
+ `${kind} edges read as ${direction(sink.directed)} per onMixedDirection`,
1091
+ where,
1092
+ `${DIRECTION_FORCED_CODE}:${kind}`
1093
+ );
1094
+ const e = sink.addEdge(source, target, weight);
1095
+ this.track(e);
1096
+ if (this.directedHandle !== INVALID_INDEX) {
1097
+ sink.setEdgeValue(this.directedHandle, e, sink.directed);
1098
+ }
1099
+ return e;
1100
+ }
1101
+ case "error":
1102
+ this.report.error(
1103
+ "validation-error",
1104
+ MIXED_DIRECTION_CODE,
1105
+ `${kind} edge in a ${direction(sink.directed)} graph (onMixedDirection: "error")`,
1106
+ where
1107
+ );
1108
+ throw this.report.abort("mixed direction refused", { code: MIXED_DIRECTION_CODE });
1109
+ case "expand":
1110
+ return this.expand(source, target, kind, weight, where);
1111
+ default: {
1112
+ const name = this.policy;
1113
+ throw new GraphFormatError("E_UNSUPPORTED", `unknown onMixedDirection ${name}`, {
1114
+ option: "onMixedDirection",
1115
+ found: name
1116
+ });
1117
+ }
1118
+ }
1119
+ }
1120
+ /**
1121
+ * How many edges were given a direction other than their own, under `onMixedDirection`
1122
+ * "directed" or "undirected".
1123
+ * @returns the count
1124
+ */
1125
+ get forced() {
1126
+ return this.forcedCount;
1127
+ }
1128
+ /**
1129
+ * Expand one edge that differs from the sink's direction.
1130
+ * @param source - the source id
1131
+ * @param target - the target id
1132
+ * @param kind - the edge's direction in the file
1133
+ * @param weight - the weight, or undefined
1134
+ * @param where - the line and element, for issues
1135
+ * @returns the primary edge index
1136
+ */
1137
+ expand(source, target, kind, weight, where) {
1138
+ const { sink } = this;
1139
+ if (!sink.directed) {
1140
+ try {
1141
+ const before = sink.edgeCount;
1142
+ sink.setDirected(true, { expand: true });
1143
+ this.adoptExpansionColumns();
1144
+ this.report.counts.expandedMixed += before;
1145
+ } catch (err) {
1146
+ if (!(err instanceof GraphFormatError) || err.code !== "E_DIRECTED") {
1147
+ throw err;
1148
+ }
1149
+ this.report.error(
1150
+ "coercion",
1151
+ DIRECTION_REFUSED_CODE,
1152
+ `${direction(true)} edge in a locked ${direction(false)} sink cannot be expanded`,
1153
+ where
1154
+ );
1155
+ throw this.report.abort("the sink refused the expansion to directed", {
1156
+ code: DIRECTION_REFUSED_CODE,
1157
+ reason: err.details.reason
1158
+ });
1159
+ }
1160
+ if (kind === "directed") {
1161
+ const e = sink.addEdge(source, target, weight);
1162
+ this.track(e);
1163
+ sink.setEdgeValue(this.directedHandle, e, true);
1164
+ return e;
1165
+ }
1166
+ }
1167
+ this.ensureExpansionColumns();
1168
+ const first = sink.addEdge(source, target, weight);
1169
+ this.track(first);
1170
+ const mutual = kind === "mutual";
1171
+ sink.setEdgeValue(this.directedHandle, first, mutual);
1172
+ this.report.counts.expandedMixed++;
1173
+ if (mutual) {
1174
+ this.ensureMutualColumn();
1175
+ sink.setEdgeValue(this.mutualHandle, first, true);
1176
+ }
1177
+ const u = sink.indexOf(source);
1178
+ const v = sink.indexOf(target);
1179
+ if (u === v) {
1180
+ return first;
1181
+ }
1182
+ const mirror = sink.addEdge(target, source, weight);
1183
+ this.track(mirror);
1184
+ this.mirrorOfLast = mirror;
1185
+ sink.setEdgeValue(this.directedHandle, mirror, mutual);
1186
+ sink.setEdgeValue(this.pairHandle, first, mirror);
1187
+ sink.setEdgeValue(this.pairHandle, mirror, first);
1188
+ return first;
1189
+ }
1190
+ /**
1191
+ * Note an edge index this resolver pushed, for the backfill of graphty.directed.
1192
+ * @param e - the edge index
1193
+ */
1194
+ track(e) {
1195
+ if (this.firstEdge < 0) {
1196
+ this.firstEdge = e;
1197
+ }
1198
+ this.nextEdge = e + 1;
1199
+ }
1200
+ /**
1201
+ * Pick up the reserved columns the builder wrote during its own expansion.
1202
+ */
1203
+ adoptExpansionColumns() {
1204
+ this.directedHandle = this.sink.declareEdgeColumn(DIRECTED_DECL);
1205
+ this.pairHandle = this.sink.declareEdgeColumn(PAIR_DECL);
1206
+ }
1207
+ /**
1208
+ * Declare the reserved columns on first use in a directed sink and backfill graphty.directed
1209
+ * = true for every edge this resolver pushed so far (they were directed in the source).
1210
+ */
1211
+ ensureExpansionColumns() {
1212
+ if (this.pairHandle !== INVALID_INDEX) {
1213
+ return;
1214
+ }
1215
+ this.directedHandle = this.sink.declareEdgeColumn(DIRECTED_DECL);
1216
+ this.pairHandle = this.sink.declareEdgeColumn(PAIR_DECL);
1217
+ if (this.firstEdge >= 0) {
1218
+ for (let e = this.firstEdge; e < this.nextEdge; e++) {
1219
+ this.sink.setEdgeValue(this.directedHandle, e, true);
1220
+ }
1221
+ }
1222
+ }
1223
+ /** Declare graphty.mutual on first use. */
1224
+ ensureMutualColumn() {
1225
+ if (this.mutualHandle === INVALID_INDEX) {
1226
+ this.mutualHandle = this.sink.declareEdgeColumn(MUTUAL_DECL);
1227
+ }
1228
+ }
1229
+ }
1230
+ function reasonOf(err) {
1231
+ const { reason } = err.details;
1232
+ return typeof reason === "string" ? reason : "refused";
1233
+ }
1234
+ function direction(directed) {
1235
+ return directed ? "directed" : "undirected";
1236
+ }
1237
+ function pairFolding(snapshot, options = {}) {
1238
+ const foldMutual = options.foldMutual ?? false;
1239
+ const directedColumn = roleColumn(snapshot.edges.byRole("directed"), "bool");
1240
+ const pairColumn = roleColumn(snapshot.edges.byRole("pair"), "u32");
1241
+ const mutualColumn = roleColumn(snapshot.edges.byRole("mutual"), "bool");
1242
+ const { edgeCount } = snapshot;
1243
+ const mateOf = (e) => {
1244
+ if (pairColumn === null || !pairColumn.isSet(e)) {
1245
+ return INVALID_INDEX;
1246
+ }
1247
+ const mate = pairColumn.value(e);
1248
+ return typeof mate === "number" && mate !== INVALID_INDEX ? mate : INVALID_INDEX;
1249
+ };
1250
+ const sourceDirected = (e) => directedColumn === null || !directedColumn.isSet(e) || directedColumn.value(e) === true;
1251
+ const isMutual = (e) => {
1252
+ if (mutualColumn === null) {
1253
+ return false;
1254
+ }
1255
+ if (mutualColumn.isSet(e) && mutualColumn.value(e) === true) {
1256
+ return true;
1257
+ }
1258
+ const mate = mateOf(e);
1259
+ return mate !== INVALID_INDEX && mutualColumn.isSet(mate) && mutualColumn.value(mate) === true;
1260
+ };
1261
+ const folded = (e) => {
1262
+ const mate = mateOf(e);
1263
+ if (mate === INVALID_INDEX || mate >= e) {
1264
+ return false;
1265
+ }
1266
+ return !sourceDirected(e) || foldMutual && isMutual(e);
1267
+ };
1268
+ let mutualCount = 0;
1269
+ if (mutualColumn !== null) {
1270
+ for (let e = 0; e < edgeCount; e++) {
1271
+ if (mutualColumn.isSet(e) && mutualColumn.value(e) === true && mateOf(e) > e) {
1272
+ mutualCount++;
1273
+ }
1274
+ }
1275
+ }
1276
+ return { expanded: pairColumn !== null, mutualCount, folded, mateOf, sourceDirected, isMutual };
1277
+ }
1278
+ function roleColumn(column, dtype) {
1279
+ return column !== null && column.dtype === dtype ? column : null;
1280
+ }
1281
+ const CANONICAL_INTEGER = /^-?(0|[1-9][0-9]*)$/;
1282
+ function canonicalId(text) {
1283
+ if (text !== "-0" && CANONICAL_INTEGER.test(text)) {
1284
+ const n = Number(text);
1285
+ if (Number.isSafeInteger(n)) {
1286
+ return n;
1287
+ }
1288
+ }
1289
+ return text;
1290
+ }
1291
+ function isCanonicalIntegerText(text) {
1292
+ return typeof canonicalId(text) === "number";
1293
+ }
1294
+ function coerceIdText(text, mode) {
1295
+ switch (mode) {
1296
+ case "keep":
1297
+ case "string":
1298
+ return text;
1299
+ case "canonical":
1300
+ return canonicalId(text);
1301
+ case "number": {
1302
+ if (text.trim().length === 0) {
1303
+ throw invalidId(text, "empty text is not a number");
1304
+ }
1305
+ const n = Number(text);
1306
+ if (!Number.isFinite(n)) {
1307
+ throw invalidId(text, "not a finite number");
1308
+ }
1309
+ return n;
1310
+ }
1311
+ default: {
1312
+ const name = mode;
1313
+ throw new GraphFormatError("E_UNSUPPORTED", `unknown id coercion ${name}`, { option: "ids", found: name });
1314
+ }
1315
+ }
1316
+ }
1317
+ function coerceId(value, mode) {
1318
+ if (typeof value === "string") {
1319
+ return coerceIdText(value, mode);
1320
+ }
1321
+ if (typeof value === "number") {
1322
+ if (!Number.isFinite(value)) {
1323
+ throw invalidId(value, "not a finite number");
1324
+ }
1325
+ return mode === "string" ? String(value) : value;
1326
+ }
1327
+ if (mode === "string" && (typeof value === "boolean" || typeof value === "bigint" || value === null)) {
1328
+ return String(value);
1329
+ }
1330
+ throw invalidId(value, `a ${value === null ? "null" : typeof value} is not an id under ids: "${mode}"`);
1331
+ }
1332
+ function invalidId(value, reason) {
1333
+ const shown = typeof value === "string" || typeof value === "number" ? value : typeof value;
1334
+ return new GraphFormatError("E_INVALID_ID", `invalid node id ${JSON.stringify(shown)}: ${reason}`, {
1335
+ reason,
1336
+ value: typeof value === "bigint" ? value.toString() : value
1337
+ });
1338
+ }
1339
+ class IdCoercer {
1340
+ /**
1341
+ * Create a coercer.
1342
+ * @param mode - the rule
1343
+ */
1344
+ constructor(mode) {
1345
+ this.mergeCount = 0;
1346
+ this.lastMerge = null;
1347
+ this.mode = mode;
1348
+ this.firstText = mode === "number" ? /* @__PURE__ */ new Map() : null;
1349
+ }
1350
+ /**
1351
+ * Coerce a text cell, recording a merge under "number" when a different text already produced
1352
+ * the same number.
1353
+ * @param text - the cell text
1354
+ * @returns the id
1355
+ */
1356
+ text(text) {
1357
+ const id = coerceIdText(text, this.mode);
1358
+ this.lastMerge = null;
1359
+ if (this.firstText !== null && typeof id === "number") {
1360
+ const previous = this.firstText.get(id);
1361
+ if (previous === void 0) {
1362
+ this.firstText.set(id, text);
1363
+ } else if (previous !== text) {
1364
+ this.mergeCount++;
1365
+ this.lastMerge = { id, text, previousText: previous };
1366
+ }
1367
+ }
1368
+ return id;
1369
+ }
1370
+ /**
1371
+ * Coerce a typed value.
1372
+ * @param value - the value
1373
+ * @returns the id
1374
+ */
1375
+ value(value) {
1376
+ if (typeof value === "string") {
1377
+ return this.text(value);
1378
+ }
1379
+ this.lastMerge = null;
1380
+ return coerceId(value, this.mode);
1381
+ }
1382
+ }
1383
+ const HEAD_BYTES = 1024;
1384
+ const BOM_BYTES = 4;
1385
+ function canonicalEncoding(label) {
1386
+ try {
1387
+ return new TextDecoder(label.trim()).encoding;
1388
+ } catch {
1389
+ return null;
1390
+ }
1391
+ }
1392
+ function bomEncoding(head) {
1393
+ if (startsWithBytes(head, [255, 254, 0, 0])) {
1394
+ return "utf-32le";
1395
+ }
1396
+ if (startsWithBytes(head, [0, 0, 254, 255])) {
1397
+ return "utf-32be";
1398
+ }
1399
+ if (startsWithBytes(head, [239, 187, 191])) {
1400
+ return "utf-8";
1401
+ }
1402
+ if (startsWithBytes(head, [255, 254])) {
1403
+ return "utf-16le";
1404
+ }
1405
+ if (startsWithBytes(head, [254, 255])) {
1406
+ return "utf-16be";
1407
+ }
1408
+ return null;
1409
+ }
1410
+ function startsWithBytes(bytes, signature) {
1411
+ return bytes.byteLength >= signature.length && signature.every((b, i) => bytes[i] === b);
1412
+ }
1413
+ function bomlessUtf16(head) {
1414
+ const pairs = Math.min(head.byteLength >> 1, 512);
1415
+ if (pairs < 2) {
1416
+ return null;
1417
+ }
1418
+ let le = 0;
1419
+ let be = 0;
1420
+ for (let i = 0; i < pairs; i++) {
1421
+ const even = head[2 * i];
1422
+ const odd = head[2 * i + 1];
1423
+ if (even !== 0 && odd === 0) {
1424
+ le++;
1425
+ } else if (even === 0 && odd !== 0) {
1426
+ be++;
1427
+ }
1428
+ }
1429
+ if (le >= pairs * 0.9) {
1430
+ return "utf-16le";
1431
+ }
1432
+ return be >= pairs * 0.9 ? "utf-16be" : null;
1433
+ }
1434
+ function xmlDeclarationUtf16(head) {
1435
+ if (startsWithBytes(head, [60, 0, 63, 0])) {
1436
+ return "utf-16le";
1437
+ }
1438
+ return startsWithBytes(head, [0, 60, 0, 63]) ? "utf-16be" : null;
1439
+ }
1440
+ function foreignKind(head) {
1441
+ if (typeof head !== "string") {
1442
+ if (startsWithBytes(head, [31, 139])) {
1443
+ return "gzip-compressed data (decompress it first)";
1444
+ }
1445
+ if (startsWithBytes(head, [80, 75, 3, 4]) || startsWithBytes(head, [80, 75, 5, 6])) {
1446
+ return "a zip archive (a Cytoscape session (.cys) is read by the cys importer; extract any other graph file from it first)";
1447
+ }
1448
+ if (startsWithBytes(head, [137, 80, 78, 71])) {
1449
+ return "a PNG image";
1450
+ }
1451
+ }
1452
+ const text = typeof head === "string" ? head.slice(0, 64) : String.fromCodePoint(...head.subarray(0, 64));
1453
+ const utf8Bom = String.fromCodePoint(239, 187, 191);
1454
+ let body = text.startsWith(utf8Bom) ? text.slice(3) : text;
1455
+ body = body.startsWith(BOM) ? body.slice(1) : body;
1456
+ if (body.startsWith("%PDF-")) {
1457
+ return "a PDF document";
1458
+ }
1459
+ if (/^\s*(<!doctype\s+html[\s>]|<html[\s>])/i.test(body)) {
1460
+ return "an HTML document (likely an error page saved in place of the file)";
1461
+ }
1462
+ return null;
1463
+ }
1464
+ function refuseForeign(head, report, options) {
1465
+ const foreign = foreignKind(head);
1466
+ if (foreign !== null && !(options.xml === true && foreign.startsWith("an HTML"))) {
1467
+ report.fail(FOREIGN_FORMAT_CODE, `the input is ${foreign}, not ${report.format} text`);
1468
+ }
1469
+ }
1470
+ function sameFamily(a, b) {
1471
+ return a === b || a.startsWith("utf-16") && b.startsWith("utf-16");
1472
+ }
1473
+ class ByteDecoder {
1474
+ /**
1475
+ * Create the decoder of one import.
1476
+ * @param report - where warnings and the fatal decode error go
1477
+ * @param options - the encoding option and the format's declaration reader
1478
+ */
1479
+ constructor(report, options) {
1480
+ this.report = report;
1481
+ this.options = options;
1482
+ this.decoder = null;
1483
+ this.encoding = "utf-8";
1484
+ this.mayFallBack = false;
1485
+ this.asciiSoFar = true;
1486
+ this.carry = new Uint8Array(0);
1487
+ this.offset = 0;
1488
+ this.fellBack = false;
1489
+ this.control = null;
1490
+ this.subAt = -1;
1491
+ this.textFollows = false;
1492
+ this.declaredUtf8 = false;
1493
+ this.mixedPending = false;
1494
+ }
1495
+ /**
1496
+ * Whether start() ran.
1497
+ * @returns true once the encoding is chosen
1498
+ */
1499
+ get started() {
1500
+ return this.decoder !== null;
1501
+ }
1502
+ /**
1503
+ * Choose the encoding from the first bytes of the input: a BOM, else the option, else the
1504
+ * declaration, else UTF-8 (see the module comment), warning where two of them disagree.
1505
+ * @param head - the first bytes (up to the declaration size; fewer when the input is shorter)
1506
+ */
1507
+ start(head) {
1508
+ refuseForeign(head, this.report, this.options);
1509
+ const explicit = this.options.encoding ?? null;
1510
+ const bom = bomEncoding(head);
1511
+ if (bom === "utf-32le" || bom === "utf-32be") {
1512
+ this.report.fail(
1513
+ INVALID_ENCODING_CODE,
1514
+ `the input starts with a ${bom.toUpperCase()} byte order mark; UTF-32 is not supported (convert the file to UTF-8)`,
1515
+ void 0,
1516
+ { byteOffset: 0 }
1517
+ );
1518
+ }
1519
+ if (bom !== null) {
1520
+ const option = explicit === null ? null : canonicalEncoding(explicit);
1521
+ if (option !== null && option !== bom) {
1522
+ this.conflict(`the encoding option says ${option} but the byte order mark says ${bom}; read as ${bom}`);
1523
+ }
1524
+ this.checkDeclaration(head, bom, "its byte order mark says");
1525
+ this.use(bom, false);
1526
+ return;
1527
+ }
1528
+ if (explicit !== null) {
1529
+ this.use(explicit, false);
1530
+ this.checkDeclaration(head, this.encoding, "the encoding option says");
1531
+ return;
1532
+ }
1533
+ const xmlUtf16 = xmlDeclarationUtf16(head);
1534
+ if (xmlUtf16 !== null) {
1535
+ this.checkDeclaration(head, xmlUtf16, "its XML declaration's byte pattern says");
1536
+ this.use(xmlUtf16, false);
1537
+ return;
1538
+ }
1539
+ const utf16 = bomlessUtf16(head);
1540
+ if (utf16 !== null && this.options.bomlessUtf16 === true) {
1541
+ this.use(utf16, false);
1542
+ return;
1543
+ }
1544
+ if (utf16 !== null) {
1545
+ this.report.fail(
1546
+ INVALID_ENCODING_CODE,
1547
+ `the input looks like ${utf16} text without a byte order mark (every other byte is 0); pass the encoding option ${JSON.stringify(utf16)} to read it`,
1548
+ void 0,
1549
+ { byteOffset: 0 }
1550
+ );
1551
+ }
1552
+ const declared = this.declared(head, "windows-1252");
1553
+ if (declared !== null) {
1554
+ const canonical = canonicalEncoding(declared);
1555
+ if (canonical === null) {
1556
+ this.report.warning(
1557
+ "unsupported",
1558
+ UNKNOWN_ENCODING_CODE,
1559
+ `the input declares the encoding ${JSON.stringify(declared)}, which this platform cannot decode; reading it as UTF-8`,
1560
+ { element: declared }
1561
+ );
1562
+ } else if (canonical.startsWith("utf-16")) {
1563
+ this.conflict(
1564
+ `the input declares ${JSON.stringify(declared)} but has no byte order mark and its bytes are not UTF-16; read as UTF-8`
1565
+ );
1566
+ } else if (canonical === "utf-8") {
1567
+ this.declaredUtf8 = true;
1568
+ } else {
1569
+ this.use(canonical, false);
1570
+ return;
1571
+ }
1572
+ }
1573
+ this.use("utf-8", true);
1574
+ }
1575
+ /**
1576
+ * The encoding the head declares, read through the format's declaration reader.
1577
+ * @param head - the first bytes
1578
+ * @param encoding - the encoding to read the head in for the reader
1579
+ * @returns the declared label, or null (also for a format without declarations)
1580
+ */
1581
+ declared(head, encoding) {
1582
+ const reader = this.options.declaredEncoding;
1583
+ return reader === void 0 ? null : reader(new TextDecoder(encoding).decode(head));
1584
+ }
1585
+ /**
1586
+ * Warn when the file declares an encoding other than the one a BOM or the option chose.
1587
+ * @param head - the first bytes
1588
+ * @param chosen - the encoding the input is read in
1589
+ * @param why - what chose it, for the message
1590
+ */
1591
+ checkDeclaration(head, chosen, why) {
1592
+ const declared = this.declared(head, chosen);
1593
+ const canonical = declared === null ? null : canonicalEncoding(declared);
1594
+ if (canonical !== null && !sameFamily(canonical, chosen)) {
1595
+ this.conflict(
1596
+ `the input declares the encoding ${JSON.stringify(declared)} but ${why} ${chosen}; read as ${chosen}`
1597
+ );
1598
+ }
1599
+ }
1600
+ /**
1601
+ * Record a W_ENCODING_CONFLICT warning.
1602
+ * @param message - which sources disagree and which applies
1603
+ */
1604
+ conflict(message) {
1605
+ this.report.warning("coercion", ENCODING_CONFLICT_CODE, message);
1606
+ }
1607
+ /**
1608
+ * Decode the next bytes.
1609
+ * @param input - the bytes
1610
+ * @param stream - whether more bytes follow
1611
+ * @returns the text
1612
+ */
1613
+ decode(input, stream) {
1614
+ const bytes = typeof SharedArrayBuffer === "function" && input.buffer instanceof SharedArrayBuffer ? input.slice() : input;
1615
+ const decoder = this.decoder;
1616
+ if (this.fellBack || this.mayFallBack && this.asciiSoFar) {
1617
+ this.watch(bytes, !stream);
1618
+ if (this.fellBack && this.control !== null) {
1619
+ this.binary(this.control);
1620
+ }
1621
+ }
1622
+ const text = this.decodeOrRecover(decoder, bytes, stream);
1623
+ if (this.mixedPending) {
1624
+ this.reportUtf8After(bytes, this.offset);
1625
+ }
1626
+ if (this.asciiSoFar && this.mayFallBack) {
1627
+ this.trackAscii(bytes, text);
1628
+ }
1629
+ if (this.mayFallBack && this.options.nulIsBinary === true && text.includes("\0")) {
1630
+ this.binary({ at: this.offset + bytes.indexOf(0), byte: 0 });
1631
+ }
1632
+ this.offset += bytes.byteLength;
1633
+ return text;
1634
+ }
1635
+ /**
1636
+ * Decode bytes, recovering from bytes that are not valid in the encoding.
1637
+ * @param decoder - the decoder
1638
+ * @param bytes - the bytes
1639
+ * @param stream - whether more bytes follow
1640
+ * @returns the text
1641
+ */
1642
+ decodeOrRecover(decoder, bytes, stream) {
1643
+ try {
1644
+ return decoder.decode(bytes, { stream });
1645
+ } catch (err) {
1646
+ if (!(err instanceof TypeError)) {
1647
+ throw err;
1648
+ }
1649
+ return this.recover(bytes, stream);
1650
+ }
1651
+ }
1652
+ /**
1653
+ * Track whether the input is ASCII so far. While it is, every character is one byte, so the
1654
+ * bytes not yet emitted are held back for a fallback.
1655
+ * @param bytes - the bytes just decoded
1656
+ * @param text - their text
1657
+ */
1658
+ trackAscii(bytes, text) {
1659
+ if (/[\u0080-\uffff]/.test(text)) {
1660
+ this.asciiSoFar = false;
1661
+ this.carry = new Uint8Array(0);
1662
+ return;
1663
+ }
1664
+ const all = this.carry.byteLength === 0 ? bytes : concatBytes([this.carry, bytes]);
1665
+ this.carry = all.slice(text.length);
1666
+ }
1667
+ /**
1668
+ * Flush the bytes held back because a text chunk follows (the input switches from bytes to
1669
+ * strings): a multi-byte sequence cut there is invalid UTF-8, never windows-1252 text.
1670
+ * @param flush - the flush to run (the decoder's own, or the head's)
1671
+ * @returns the text of the held-back bytes
1672
+ */
1673
+ flushBeforeText(flush) {
1674
+ this.textFollows = true;
1675
+ try {
1676
+ return flush();
1677
+ } finally {
1678
+ this.textFollows = false;
1679
+ }
1680
+ }
1681
+ /**
1682
+ * A decode failed: switch to windows-1252 when allowed, else fail the import with the position
1683
+ * of the first byte that is not valid.
1684
+ * @param bytes - the bytes that failed
1685
+ * @param stream - whether more bytes follow
1686
+ * @returns the bytes decoded as windows-1252
1687
+ */
1688
+ recover(bytes, stream) {
1689
+ const all = this.carry.byteLength === 0 ? bytes : concatBytes([this.carry, bytes]);
1690
+ const base = this.offset - this.carry.byteLength;
1691
+ const bad = this.encoding === "utf-8" ? invalidUtf8(all) : null;
1692
+ const at = base + (bad === null ? 0 : bad.index);
1693
+ if (this.mayFallBack && this.asciiSoFar) {
1694
+ if (this.control !== null) {
1695
+ return this.binary(this.control);
1696
+ }
1697
+ if (this.textFollows && bad?.cut === true) {
1698
+ return this.report.fail(
1699
+ INVALID_UTF8_CODE,
1700
+ `invalid UTF-8 at byte ${at}: a byte chunk ends inside a multi-byte sequence and a text chunk follows`,
1701
+ void 0,
1702
+ { byteOffset: at }
1703
+ );
1704
+ }
1705
+ if (!stream && bad?.truncated === true) {
1706
+ return this.report.fail(
1707
+ INVALID_UTF8_CODE,
1708
+ `the input ends in the middle of a UTF-8 sequence at byte ${at} (it may be truncated)`,
1709
+ void 0,
1710
+ { byteOffset: at }
1711
+ );
1712
+ }
1713
+ if (!startsWithUtf8(all)) {
1714
+ const cutNote = !stream && bad?.cut === true ? ": it ends inside a multi-byte UTF-8 sequence, so it may be truncated" : "";
1715
+ this.report.warning(
1716
+ "coercion",
1717
+ ENCODING_FALLBACK_CODE,
1718
+ this.declaredUtf8 ? `the input declares UTF-8 but is not valid UTF-8 (at byte ${at}); everything before was ASCII, so it is read as windows-1252 (pass the encoding option to choose another)` : `the input is not valid UTF-8 (at byte ${at}${cutNote}) and declares no encoding; read as windows-1252 (pass the encoding option to choose another)`
1719
+ );
1720
+ this.use("windows-1252", false);
1721
+ this.fellBack = true;
1722
+ this.mixedPending = true;
1723
+ this.reportUtf8After(all, base);
1724
+ return this.decoder.decode(all, { stream });
1725
+ }
1726
+ }
1727
+ if (this.encoding === "utf-8") {
1728
+ const after = this.mayFallBack ? " after valid non-ASCII UTF-8 text; pass the encoding option" : "";
1729
+ return this.report.fail(INVALID_UTF8_CODE, `invalid UTF-8 at byte ${at}${after}`, void 0, {
1730
+ byteOffset: at
1731
+ });
1732
+ }
1733
+ const end = this.offset + bytes.byteLength;
1734
+ const odd = !stream && this.encoding.startsWith("utf-16") && end % 2 === 1;
1735
+ return this.report.fail(
1736
+ INVALID_ENCODING_CODE,
1737
+ odd ? `the input ends with half a ${this.encoding} code unit at byte ${end - 1} (it may be truncated)` : `the bytes near byte ${base} are not valid ${this.encoding}`,
1738
+ void 0,
1739
+ { byteOffset: odd ? end - 1 : base }
1740
+ );
1741
+ }
1742
+ /**
1743
+ * After the windows-1252 fallback, report once that later bytes hold a valid multi-byte UTF-8
1744
+ * sequence: the input mixes encodings, and those characters are read as two or three
1745
+ * windows-1252 characters each.
1746
+ * @param bytes - bytes being decoded as windows-1252
1747
+ * @param start - the byte offset of the first of them
1748
+ */
1749
+ reportUtf8After(bytes, start) {
1750
+ const at = utf8SequenceIndex(bytes);
1751
+ if (at < 0) {
1752
+ return;
1753
+ }
1754
+ this.mixedPending = false;
1755
+ this.report.warning(
1756
+ "coercion",
1757
+ ENCODING_FALLBACK_CODE,
1758
+ `bytes read as windows-1252 hold valid UTF-8 (at byte ${start + at}): the input mixes encodings, and its UTF-8 characters are read as windows-1252 (pass the encoding option to choose one)`
1759
+ );
1760
+ }
1761
+ /**
1762
+ * Note the first control byte of the next bytes (see `control`).
1763
+ * @param bytes - the bytes, starting at `offset`
1764
+ * @param final - whether they end the input
1765
+ */
1766
+ watch(bytes, final) {
1767
+ if (this.control !== null || bytes.byteLength === 0) {
1768
+ return;
1769
+ }
1770
+ if (this.subAt >= 0) {
1771
+ this.control = { at: this.subAt, byte: 26 };
1772
+ return;
1773
+ }
1774
+ const index = controlByte(bytes, true);
1775
+ if (index >= 0) {
1776
+ this.control = { at: this.offset + index, byte: bytes[index] };
1777
+ } else if (!final && bytes[bytes.byteLength - 1] === 26) {
1778
+ this.subAt = this.offset + bytes.byteLength - 1;
1779
+ }
1780
+ }
1781
+ /**
1782
+ * Fail the import as binary data.
1783
+ * @param control - the control byte that shows it
1784
+ * @param control.at - its offset
1785
+ * @param control.byte - its value
1786
+ * @returns never
1787
+ */
1788
+ binary(control) {
1789
+ const hex = control.byte.toString(16).padStart(2, "0");
1790
+ return this.report.fail(
1791
+ INVALID_UTF8_CODE,
1792
+ `the input is binary data, not text: control byte 0x${hex} at byte ${control.at}`,
1793
+ void 0,
1794
+ { byteOffset: control.at }
1795
+ );
1796
+ }
1797
+ /**
1798
+ * Switch to an encoding.
1799
+ * @param label - the encoding label
1800
+ * @param mayFallBack - whether a UTF-8 failure may switch to windows-1252
1801
+ */
1802
+ use(label, mayFallBack) {
1803
+ this.decoder = new TextDecoder(label, { fatal: true, ignoreBOM: true });
1804
+ this.encoding = this.decoder.encoding;
1805
+ this.mayFallBack = mayFallBack;
1806
+ }
1807
+ }
1808
+ function utf8SequenceIndex(bytes) {
1809
+ for (let i = 0; i < bytes.byteLength; i++) {
1810
+ if (bytes[i] >= 194 && isUtf8SequenceAt(bytes, i)) {
1811
+ return i;
1812
+ }
1813
+ }
1814
+ return -1;
1815
+ }
1816
+ function startsWithUtf8(bytes) {
1817
+ const i = bytes.findIndex((b) => b >= 128);
1818
+ return i >= 0 && isUtf8SequenceAt(bytes, i);
1819
+ }
1820
+ const STRICT_UTF8 = new TextDecoder("utf-8", { fatal: true });
1821
+ function isUtf8SequenceAt(bytes, i) {
1822
+ const lead = bytes[i];
1823
+ let length = 0;
1824
+ if (lead >= 194 && lead <= 223) {
1825
+ length = 2;
1826
+ } else if (lead >= 224 && lead <= 239) {
1827
+ length = 3;
1828
+ } else if (lead >= 240 && lead <= 244) {
1829
+ length = 4;
1830
+ }
1831
+ if (length === 0 || i + length > bytes.byteLength) {
1832
+ return false;
1833
+ }
1834
+ try {
1835
+ STRICT_UTF8.decode(bytes.subarray(i, i + length));
1836
+ return true;
1837
+ } catch {
1838
+ return false;
1839
+ }
1840
+ }
1841
+ const CP437_HIGH = [
1842
+ 199,
1843
+ 252,
1844
+ 233,
1845
+ 226,
1846
+ 228,
1847
+ 224,
1848
+ 229,
1849
+ 231,
1850
+ 234,
1851
+ 235,
1852
+ 232,
1853
+ 239,
1854
+ 238,
1855
+ 236,
1856
+ 196,
1857
+ 197,
1858
+ 201,
1859
+ 230,
1860
+ 198,
1861
+ 244,
1862
+ 246,
1863
+ 242,
1864
+ 251,
1865
+ 249,
1866
+ 255,
1867
+ 214,
1868
+ 220,
1869
+ 162,
1870
+ 163,
1871
+ 165,
1872
+ 8359,
1873
+ 402,
1874
+ 225,
1875
+ 237,
1876
+ 243,
1877
+ 250,
1878
+ 241,
1879
+ 209,
1880
+ 170,
1881
+ 186,
1882
+ 191,
1883
+ 8976,
1884
+ 172,
1885
+ 189,
1886
+ 188,
1887
+ 161,
1888
+ 171,
1889
+ 187,
1890
+ 9617,
1891
+ 9618,
1892
+ 9619,
1893
+ 9474,
1894
+ 9508,
1895
+ 9569,
1896
+ 9570,
1897
+ 9558,
1898
+ 9557,
1899
+ 9571,
1900
+ 9553,
1901
+ 9559,
1902
+ 9565,
1903
+ 9564,
1904
+ 9563,
1905
+ 9488,
1906
+ 9492,
1907
+ 9524,
1908
+ 9516,
1909
+ 9500,
1910
+ 9472,
1911
+ 9532,
1912
+ 9566,
1913
+ 9567,
1914
+ 9562,
1915
+ 9556,
1916
+ 9577,
1917
+ 9574,
1918
+ 9568,
1919
+ 9552,
1920
+ 9580,
1921
+ 9575,
1922
+ 9576,
1923
+ 9572,
1924
+ 9573,
1925
+ 9561,
1926
+ 9560,
1927
+ 9554,
1928
+ 9555,
1929
+ 9579,
1930
+ 9578,
1931
+ 9496,
1932
+ 9484,
1933
+ 9608,
1934
+ 9604,
1935
+ 9612,
1936
+ 9616,
1937
+ 9600,
1938
+ 945,
1939
+ 223,
1940
+ 915,
1941
+ 960,
1942
+ 931,
1943
+ 963,
1944
+ 181,
1945
+ 964,
1946
+ 934,
1947
+ 920,
1948
+ 937,
1949
+ 948,
1950
+ 8734,
1951
+ 966,
1952
+ 949,
1953
+ 8745,
1954
+ 8801,
1955
+ 177,
1956
+ 8805,
1957
+ 8804,
1958
+ 8992,
1959
+ 8993,
1960
+ 247,
1961
+ 8776,
1962
+ 176,
1963
+ 8729,
1964
+ 183,
1965
+ 8730,
1966
+ 8319,
1967
+ 178,
1968
+ 9632,
1969
+ 160
1970
+ ];
1971
+ function invalidUtf8(bytes) {
1972
+ let i = 0;
1973
+ while (i < bytes.byteLength) {
1974
+ const lead = bytes[i];
1975
+ const sequence = lead < 128 ? ASCII_SEQUENCE : utf8Sequence(lead);
1976
+ if (sequence === null) {
1977
+ return { index: i, truncated: false, cut: false };
1978
+ }
1979
+ const problem = checkContinuation(bytes, i, sequence);
1980
+ if (problem !== null) {
1981
+ return problem;
1982
+ }
1983
+ i += sequence.need + 1;
1984
+ }
1985
+ return { index: 0, truncated: false, cut: false };
1986
+ }
1987
+ const ASCII_SEQUENCE = { need: 0, low: 128, high: 191 };
1988
+ function utf8Sequence(lead) {
1989
+ if (lead >= 194 && lead <= 223) {
1990
+ return { need: 1, low: 128, high: 191 };
1991
+ }
1992
+ if (lead >= 224 && lead <= 239) {
1993
+ return { need: 2, low: lead === 224 ? 160 : 128, high: lead === 237 ? 159 : 191 };
1994
+ }
1995
+ if (lead >= 240 && lead <= 244) {
1996
+ return { need: 3, low: lead === 240 ? 144 : 128, high: lead === 244 ? 143 : 191 };
1997
+ }
1998
+ return null;
1999
+ }
2000
+ function checkContinuation(bytes, i, sequence) {
2001
+ for (let k = 1; k <= sequence.need; k++) {
2002
+ if (i + k >= bytes.byteLength) {
2003
+ return { index: i, truncated: k > 1, cut: true };
2004
+ }
2005
+ const next = bytes[i + k];
2006
+ const low = k === 1 ? sequence.low : 128;
2007
+ const high = k === 1 ? sequence.high : 191;
2008
+ if (next < low || next > high) {
2009
+ return { index: i, truncated: false, cut: false };
2010
+ }
2011
+ }
2012
+ return null;
2013
+ }
2014
+ function controlByte(bytes, final) {
2015
+ const last = bytes.byteLength - 1;
2016
+ return bytes.findIndex(
2017
+ (b, i) => b < 32 && b !== 9 && b !== 10 && b !== 12 && b !== 13 && !(b === 26 && final && i === last)
2018
+ );
2019
+ }
2020
+ function decodeEntryName(bytes, cp437 = false) {
2021
+ try {
2022
+ return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
2023
+ } catch {
2024
+ if (!cp437) {
2025
+ return new TextDecoder("windows-1252").decode(bytes);
2026
+ }
2027
+ let out = "";
2028
+ for (const byte of bytes) {
2029
+ out += String.fromCodePoint(byte < 128 ? byte : CP437_HIGH[byte - 128]);
2030
+ }
2031
+ return out;
2032
+ }
2033
+ }
2034
+ function concatBytes(chunks) {
2035
+ if (chunks.length === 1) {
2036
+ return chunks[0];
2037
+ }
2038
+ const out = new Uint8Array(chunks.reduce((sum, c) => sum + c.byteLength, 0));
2039
+ let offset = 0;
2040
+ for (const chunk of chunks) {
2041
+ out.set(chunk, offset);
2042
+ offset += chunk.byteLength;
2043
+ }
2044
+ return out;
2045
+ }
2046
+ const DECODE_SLICE = 256 * 1024;
2047
+ const BOM = String.fromCharCode(65279);
2048
+ const SUB = String.fromCodePoint(26);
2049
+ const MAX_TEXT_LENGTH = 2 ** 29 - 24;
2050
+ const CONTROL_CHARACTER = new RegExp(
2051
+ `[${String.fromCodePoint(0)}-${String.fromCodePoint(8, 11, 14)}-${String.fromCodePoint(31, 127)}-${String.fromCodePoint(159)}${BOM}]`
2052
+ );
2053
+ function isImportInput(input) {
2054
+ if (typeof input === "string" || asBytes(input) !== null) {
2055
+ return true;
2056
+ }
2057
+ if (typeof input !== "object" || input === null) {
2058
+ return false;
2059
+ }
2060
+ return typeof input.getReader === "function" || Symbol.asyncIterator in input;
2061
+ }
2062
+ function asBytes(value) {
2063
+ if (value instanceof Uint8Array) {
2064
+ return value;
2065
+ }
2066
+ if (ArrayBuffer.isView(value) && Object.prototype.toString.call(value) === "[object Uint8Array]") {
2067
+ return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
2068
+ }
2069
+ return null;
2070
+ }
2071
+ function normalizeInput(input) {
2072
+ if (typeof input === "string") {
2073
+ return input;
2074
+ }
2075
+ const bytes = asBytes(input);
2076
+ if (bytes !== null) {
2077
+ return bytes;
2078
+ }
2079
+ if (isImportInput(input)) {
2080
+ return input;
2081
+ }
2082
+ const tag = Object.prototype.toString.call(input).slice(8, -1);
2083
+ let found = input === null ? "null" : typeof input;
2084
+ let fix = "";
2085
+ if (tag === "ArrayBuffer" || tag === "SharedArrayBuffer") {
2086
+ found = `an ${tag}`;
2087
+ fix = "; wrap it as new Uint8Array(buffer)";
2088
+ } else if (ArrayBuffer.isView(input)) {
2089
+ found = `a ${tag}`;
2090
+ fix = "; pass new Uint8Array(view.buffer, view.byteOffset, view.byteLength)";
2091
+ } else if (typeof input === "object" && input !== null) {
2092
+ const object = input;
2093
+ if (typeof object.stream === "function" && typeof object.size === "number") {
2094
+ found = "a Blob or File";
2095
+ fix = "; pass blob.stream()";
2096
+ } else if ("body" in object && typeof object.arrayBuffer === "function") {
2097
+ found = "a fetch Response";
2098
+ fix = "; pass response.body";
2099
+ } else {
2100
+ found = `an object (${tag})`;
2101
+ }
2102
+ }
2103
+ throw new GraphFormatError(
2104
+ "E_UNSUPPORTED",
2105
+ `the input is ${found}; an importer reads a string, a Uint8Array, a ReadableStream or an async iterable of strings and Uint8Arrays${fix}`,
2106
+ { reason: "input type", found }
2107
+ );
2108
+ }
2109
+ function inputLength(input) {
2110
+ if (typeof input === "string") {
2111
+ return input.length;
2112
+ }
2113
+ if (input instanceof Uint8Array) {
2114
+ return input.byteLength;
2115
+ }
2116
+ return null;
2117
+ }
2118
+ function utf8Length(text) {
2119
+ let bytes = 0;
2120
+ let i = 0;
2121
+ while (i < text.length) {
2122
+ const c = text.charCodeAt(i);
2123
+ const pair = c >= 55296 && c <= 56319 && (text.charCodeAt(i + 1) & 64512) === 56320;
2124
+ if (c < 128) {
2125
+ bytes++;
2126
+ } else if (c < 2048) {
2127
+ bytes += 2;
2128
+ } else {
2129
+ bytes += pair ? 4 : 3;
2130
+ }
2131
+ i += pair ? 2 : 1;
2132
+ }
2133
+ return bytes;
2134
+ }
2135
+ function throwIfAborted(signal) {
2136
+ if (signal === null || signal === void 0 || !signal.aborted) {
2137
+ return;
2138
+ }
2139
+ const { reason } = signal;
2140
+ if (reason === void 0) {
2141
+ throw abortError();
2142
+ }
2143
+ throw reason;
2144
+ }
2145
+ function abortError() {
2146
+ const message = "The import was aborted";
2147
+ if (typeof DOMException === "function") {
2148
+ return new DOMException(message, "AbortError");
2149
+ }
2150
+ const err = new Error(message);
2151
+ err.name = "AbortError";
2152
+ return err;
2153
+ }
2154
+ function abortable(promise, signal) {
2155
+ if (signal === null || typeof signal.addEventListener !== "function") {
2156
+ return promise;
2157
+ }
2158
+ return new Promise((resolve, reject) => {
2159
+ const onAbort = () => {
2160
+ try {
2161
+ throwIfAborted(signal);
2162
+ } catch (err) {
2163
+ reject(err);
2164
+ }
2165
+ };
2166
+ signal.addEventListener("abort", onAbort, { once: true });
2167
+ promise.then(
2168
+ (value) => {
2169
+ signal.removeEventListener("abort", onAbort);
2170
+ resolve(value);
2171
+ },
2172
+ (err) => {
2173
+ signal.removeEventListener("abort", onAbort);
2174
+ reject(err);
2175
+ }
2176
+ );
2177
+ });
2178
+ }
2179
+ function lockReader(stream) {
2180
+ if (stream.locked) {
2181
+ throw new GraphFormatError(
2182
+ "E_UNSUPPORTED",
2183
+ "the input ReadableStream is locked: another reader holds it (release it, or pass a fresh stream)",
2184
+ { reason: "stream locked" }
2185
+ );
2186
+ }
2187
+ return stream.getReader();
2188
+ }
2189
+ class TextFilter {
2190
+ /**
2191
+ * Create the filter of one import.
2192
+ * @param report - where the warnings and the fatal errors go
2193
+ * @param options - whether an empty input is valid, whether the format is XML
2194
+ */
2195
+ constructor(report, options) {
2196
+ this.report = report;
2197
+ this.options = options;
2198
+ this.first = true;
2199
+ this.content = false;
2200
+ this.heldSub = false;
2201
+ this.warned = false;
2202
+ this.strayBom = false;
2203
+ }
2204
+ /**
2205
+ * Filter the next decoded text.
2206
+ * @param chunk - the text
2207
+ * @returns the text to hand on
2208
+ */
2209
+ push(chunk) {
2210
+ let text = this.heldSub ? SUB + chunk : chunk;
2211
+ this.heldSub = false;
2212
+ if (text.length === 0) {
2213
+ return text;
2214
+ }
2215
+ if (this.first) {
2216
+ text = this.skipByteOrderMarks(text);
2217
+ if (text.length === 0) {
2218
+ return text;
2219
+ }
2220
+ this.first = false;
2221
+ refuseForeign(text, this.report, this.options);
2222
+ }
2223
+ if (text.endsWith(SUB)) {
2224
+ this.heldSub = true;
2225
+ text = text.slice(0, -1);
2226
+ }
2227
+ if (!this.content && /\S/.test(text)) {
2228
+ this.content = true;
2229
+ }
2230
+ if (!this.warned) {
2231
+ this.warnControl(text);
2232
+ }
2233
+ return text;
2234
+ }
2235
+ /**
2236
+ * Drop the byte order marks the input starts with, warning when there is more than one.
2237
+ * @param text - the first text
2238
+ * @returns the text without them
2239
+ */
2240
+ skipByteOrderMarks(text) {
2241
+ let start = 0;
2242
+ while (text.codePointAt(start) === 65279) {
2243
+ start++;
2244
+ }
2245
+ if (start > 1 && !this.strayBom) {
2246
+ this.strayBom = true;
2247
+ this.report.warning(
2248
+ "validation-error",
2249
+ CONTROL_CHARACTER_CODE,
2250
+ `the input starts with ${start} byte order marks (U+FEFF); the extra ones were ignored`,
2251
+ { element: "U+FEFF" }
2252
+ );
2253
+ }
2254
+ return text.slice(start);
2255
+ }
2256
+ /**
2257
+ * Warn, once, about the first control character the text holds.
2258
+ * @param text - the text
2259
+ */
2260
+ warnControl(text) {
2261
+ const match = CONTROL_CHARACTER.exec(text);
2262
+ if (match === null) {
2263
+ return;
2264
+ }
2265
+ this.warned = true;
2266
+ const code = (match[0].codePointAt(0) ?? 0).toString(16).toUpperCase().padStart(4, "0");
2267
+ const around = JSON.stringify(text.slice(Math.max(0, match.index - 20), match.index + 20));
2268
+ this.report.warning(
2269
+ "validation-error",
2270
+ CONTROL_CHARACTER_CODE,
2271
+ `the input holds the control character U+${code} (in ${around}); it is kept in the id or value it is part of`,
2272
+ { element: `U+${code}` }
2273
+ );
2274
+ }
2275
+ /** The input ended: drop a held Ctrl-Z with a warning, and refuse an input without content. */
2276
+ end() {
2277
+ if (this.heldSub) {
2278
+ this.report.warning(
2279
+ "validation-error",
2280
+ CONTROL_CHARACTER_CODE,
2281
+ "the input ends with a Ctrl-Z (0x1A), the DOS end-of-file marker; it was ignored",
2282
+ { element: "U+001A" }
2283
+ );
2284
+ }
2285
+ if (!this.content && this.options.allowEmpty !== true) {
2286
+ this.report.fail(EMPTY_INPUT_CODE, this.first ? "the input is empty" : "the input holds only whitespace");
2287
+ }
2288
+ }
2289
+ }
2290
+ function reportTextEncoding(report, encoding) {
2291
+ if (encoding !== null && encoding !== void 0) {
2292
+ report.warning(
2293
+ "unsupported",
2294
+ OPTION_IGNORED_CODE,
2295
+ "option encoding has no effect on text input, which is already decoded",
2296
+ { element: "encoding" }
2297
+ );
2298
+ }
2299
+ }
2300
+ async function* textChunks(rawInput, report, options = {}) {
2301
+ const input = normalizeInput(rawInput);
2302
+ const signal = options.signal ?? null;
2303
+ const onProgress = options.onProgress ?? null;
2304
+ const filter = new TextFilter(report, options);
2305
+ throwIfAborted(signal);
2306
+ if (typeof input === "string") {
2307
+ reportTextEncoding(report, options.encoding);
2308
+ const total = onProgress === null ? 0 : utf8Length(input);
2309
+ let done2 = 0;
2310
+ let start = 0;
2311
+ while (start < input.length) {
2312
+ throwIfAborted(signal);
2313
+ let end = Math.min(start + DECODE_SLICE, input.length);
2314
+ const highSurrogate = (input.charCodeAt(end - 1) & 64512) === 55296;
2315
+ if (end < input.length && highSurrogate) {
2316
+ end++;
2317
+ }
2318
+ const piece = start === 0 && end === input.length ? input : input.slice(start, end);
2319
+ start = end;
2320
+ const text = filter.push(piece);
2321
+ if (text.length > 0) {
2322
+ yield text;
2323
+ }
2324
+ if (onProgress !== null) {
2325
+ done2 += utf8Length(piece);
2326
+ onProgress(done2, total);
2327
+ }
2328
+ }
2329
+ if (input.length === 0) {
2330
+ onProgress?.(0, 0);
2331
+ }
2332
+ filter.end();
2333
+ return;
2334
+ }
2335
+ const decoder = new ByteDecoder(report, options);
2336
+ const headBytes = Math.max(options.declarationBytes ?? HEAD_BYTES, BOM_BYTES);
2337
+ if (input instanceof Uint8Array) {
2338
+ const length = input.byteLength;
2339
+ decoder.start(input.subarray(0, headBytes));
2340
+ for (let offset = 0; offset < length; offset += DECODE_SLICE) {
2341
+ throwIfAborted(signal);
2342
+ if (input.byteLength !== length) {
2343
+ throw new GraphFormatError(
2344
+ "E_UNSUPPORTED",
2345
+ "the input's buffer was detached (transferred) or resized during the import",
2346
+ { reason: "detached" }
2347
+ );
2348
+ }
2349
+ const slice = input.subarray(offset, Math.min(offset + DECODE_SLICE, length));
2350
+ const text = filter.push(decoder.decode(slice, offset + DECODE_SLICE < length));
2351
+ if (text.length > 0) {
2352
+ yield text;
2353
+ }
2354
+ onProgress?.(Math.min(offset + DECODE_SLICE, length), length);
2355
+ }
2356
+ if (length === 0) {
2357
+ onProgress?.(0, 0);
2358
+ }
2359
+ filter.end();
2360
+ return;
2361
+ }
2362
+ const needed = options.declaredEncoding === void 0 ? BOM_BYTES : headBytes;
2363
+ let done = 0;
2364
+ let head = [];
2365
+ let headLength = 0;
2366
+ const flushHead = (stream) => {
2367
+ const bytes = concatBytes(head);
2368
+ head = [];
2369
+ headLength = 0;
2370
+ decoder.start(bytes.subarray(0, headBytes));
2371
+ return decoder.decode(bytes, stream);
2372
+ };
2373
+ const chunks = isReadableStream(input) ? streamChunks(input, signal) : input;
2374
+ for await (const chunk of chunks) {
2375
+ throwIfAborted(signal);
2376
+ let text;
2377
+ const bytes = typeof chunk === "string" ? null : asBytes(chunk);
2378
+ if (typeof chunk === "string") {
2379
+ let pending = "";
2380
+ if (headLength > 0) {
2381
+ pending = decoder.flushBeforeText(() => flushHead(false));
2382
+ } else if (decoder.started) {
2383
+ pending = decoder.flushBeforeText(() => decoder.decode(new Uint8Array(0), false));
2384
+ } else {
2385
+ decoder.start(new Uint8Array(0));
2386
+ }
2387
+ text = filter.push(pending + chunk);
2388
+ done += onProgress === null ? 0 : utf8Length(chunk);
2389
+ } else if (bytes !== null) {
2390
+ done += bytes.byteLength;
2391
+ if (decoder.started) {
2392
+ text = filter.push(decoder.decode(bytes, true));
2393
+ } else {
2394
+ head.push(bytes);
2395
+ headLength += bytes.byteLength;
2396
+ text = headLength >= needed ? filter.push(flushHead(true)) : "";
2397
+ }
2398
+ } else {
2399
+ throw new GraphFormatError("E_UNSUPPORTED", "an input chunk must be a string or a Uint8Array", {
2400
+ reason: "chunk type",
2401
+ found: typeof chunk
2402
+ });
2403
+ }
2404
+ if (text.length > 0) {
2405
+ yield text;
2406
+ }
2407
+ onProgress?.(done);
2408
+ }
2409
+ let tail = "";
2410
+ if (headLength > 0) {
2411
+ tail = flushHead(false);
2412
+ } else if (decoder.started) {
2413
+ tail = decoder.decode(new Uint8Array(0), false);
2414
+ }
2415
+ tail = filter.push(tail);
2416
+ if (tail.length > 0) {
2417
+ yield tail;
2418
+ }
2419
+ filter.end();
2420
+ onProgress?.(done, done);
2421
+ }
2422
+ function isReadableStream(input) {
2423
+ return typeof input.getReader === "function";
2424
+ }
2425
+ async function* streamChunks(stream, signal) {
2426
+ const reader = lockReader(stream);
2427
+ let finished = false;
2428
+ try {
2429
+ for (; ; ) {
2430
+ throwIfAborted(signal);
2431
+ const { done, value } = await abortable(reader.read(), signal);
2432
+ if (done) {
2433
+ finished = true;
2434
+ return;
2435
+ }
2436
+ yield value;
2437
+ }
2438
+ } finally {
2439
+ if (!finished) {
2440
+ await reader.cancel(signal?.reason).catch(() => void 0);
2441
+ }
2442
+ reader.releaseLock();
2443
+ }
2444
+ }
2445
+ async function readBytes(rawInput, options = {}) {
2446
+ const input = normalizeInput(rawInput);
2447
+ const signal = options.signal ?? null;
2448
+ throwIfAborted(signal);
2449
+ if (typeof input === "string") {
2450
+ return null;
2451
+ }
2452
+ if (input instanceof Uint8Array) {
2453
+ options.onProgress?.(input.byteLength, input.byteLength);
2454
+ return input;
2455
+ }
2456
+ const parts = [];
2457
+ let done = 0;
2458
+ for await (const chunk of isReadableStream(input) ? streamChunks(input, signal) : input) {
2459
+ throwIfAborted(signal);
2460
+ if (typeof chunk === "string") {
2461
+ return null;
2462
+ }
2463
+ const bytes = asBytes(chunk);
2464
+ if (bytes === null) {
2465
+ throw new GraphFormatError("E_UNSUPPORTED", "an input chunk must be a string or a Uint8Array", {
2466
+ reason: "chunk type",
2467
+ found: typeof chunk
2468
+ });
2469
+ }
2470
+ parts.push(bytes);
2471
+ done += bytes.byteLength;
2472
+ options.onProgress?.(done);
2473
+ }
2474
+ options.onProgress?.(done, done);
2475
+ return parts.length === 0 ? new Uint8Array(0) : concatBytes(parts);
2476
+ }
2477
+ function tooLarge(report, message, line) {
2478
+ report.failWith("unsupported", TOO_LARGE_CODE, message, line === void 0 ? void 0 : { line });
2479
+ }
2480
+ async function readText(rawInput, report, options = {}) {
2481
+ const input = normalizeInput(rawInput);
2482
+ if (typeof input === "string") {
2483
+ throwIfAborted(options.signal);
2484
+ reportTextEncoding(report, options.encoding);
2485
+ const filter = new TextFilter(report, options);
2486
+ const text = filter.push(input);
2487
+ filter.end();
2488
+ if (options.onProgress !== null && options.onProgress !== void 0) {
2489
+ const total = utf8Length(input);
2490
+ options.onProgress(total, total);
2491
+ }
2492
+ return text;
2493
+ }
2494
+ const parts = [];
2495
+ let length = 0;
2496
+ for await (const chunk of textChunks(input, report, options)) {
2497
+ length += chunk.length;
2498
+ if (length > MAX_TEXT_LENGTH) {
2499
+ tooLarge(
2500
+ report,
2501
+ `the document is longer than ${MAX_TEXT_LENGTH} characters, the most one JavaScript string holds`
2502
+ );
2503
+ }
2504
+ parts.push(chunk);
2505
+ }
2506
+ return parts.length === 1 ? parts[0] : parts.join("");
2507
+ }
2508
+ class LineReader {
2509
+ /**
2510
+ * Create a reader over an input; nothing is read until iteration starts.
2511
+ * @param input - the input
2512
+ * @param report - the report decode errors are recorded in
2513
+ * @param options - cancellation and progress
2514
+ */
2515
+ constructor(input, report, options = {}) {
2516
+ this.lineNumber = 0;
2517
+ this.input = input;
2518
+ this.report = report;
2519
+ this.options = options;
2520
+ }
2521
+ /**
2522
+ * The 1-based number of the line most recently yielded.
2523
+ * @returns the line number; 0 before the first line
2524
+ */
2525
+ get line() {
2526
+ return this.lineNumber;
2527
+ }
2528
+ /**
2529
+ * The E_TOO_LARGE message of a line longer than one string.
2530
+ * @returns the message
2531
+ */
2532
+ lineTooLong() {
2533
+ return `a line is longer than ${MAX_TEXT_LENGTH} characters, the most one JavaScript string holds`;
2534
+ }
2535
+ /**
2536
+ * Iterate the lines.
2537
+ * @yields one line at a time, terminator removed
2538
+ * @returns nothing
2539
+ */
2540
+ async *[Symbol.asyncIterator]() {
2541
+ const pending = [];
2542
+ let pendingLength = 0;
2543
+ let trailingCr = false;
2544
+ for await (const chunk of textChunks(this.input, this.report, this.options)) {
2545
+ let start = 0;
2546
+ const end = chunk.length;
2547
+ if (trailingCr) {
2548
+ trailingCr = false;
2549
+ this.lineNumber++;
2550
+ const joined = pending.join("");
2551
+ pending.length = 0;
2552
+ pendingLength = 0;
2553
+ yield joined.slice(0, -1);
2554
+ if (chunk.charCodeAt(0) === 10) {
2555
+ start = 1;
2556
+ }
2557
+ }
2558
+ let nl = chunk.indexOf("\n", start);
2559
+ let cr = chunk.indexOf("\r", start);
2560
+ while (nl >= 0 || cr >= 0) {
2561
+ let cut;
2562
+ let next;
2563
+ if (cr >= 0 && (nl < 0 || cr < nl)) {
2564
+ if (cr === end - 1) {
2565
+ break;
2566
+ }
2567
+ cut = cr;
2568
+ next = chunk.charCodeAt(cr + 1) === 10 ? cr + 2 : cr + 1;
2569
+ } else {
2570
+ cut = nl;
2571
+ next = nl + 1;
2572
+ }
2573
+ this.lineNumber++;
2574
+ const piece = chunk.slice(start, cut);
2575
+ if (pending.length === 0) {
2576
+ yield piece;
2577
+ } else {
2578
+ if (pendingLength + piece.length > MAX_TEXT_LENGTH) {
2579
+ tooLarge(this.report, this.lineTooLong(), this.lineNumber);
2580
+ }
2581
+ pending.push(piece);
2582
+ const joined = pending.join("");
2583
+ pending.length = 0;
2584
+ pendingLength = 0;
2585
+ yield joined;
2586
+ }
2587
+ start = next;
2588
+ if (nl >= 0 && nl < next) {
2589
+ nl = chunk.indexOf("\n", next);
2590
+ }
2591
+ if (cr >= 0 && cr < next) {
2592
+ cr = chunk.indexOf("\r", next);
2593
+ }
2594
+ }
2595
+ if (start < end) {
2596
+ pendingLength += end - start;
2597
+ if (pendingLength > MAX_TEXT_LENGTH) {
2598
+ tooLarge(this.report, this.lineTooLong(), this.lineNumber + 1);
2599
+ }
2600
+ pending.push(start === 0 ? chunk : chunk.slice(start));
2601
+ trailingCr = chunk.charCodeAt(end - 1) === 13;
2602
+ }
2603
+ }
2604
+ if (pending.length > 0) {
2605
+ this.lineNumber++;
2606
+ const joined = pending.join("");
2607
+ yield joined.endsWith("\r") ? joined.slice(0, -1) : joined;
2608
+ }
2609
+ }
2610
+ }
2611
+ const ID_COERCIONS = /* @__PURE__ */ new Set(["keep", "canonical", "string", "number"]);
2612
+ const NODE_ID_SOURCES = /* @__PURE__ */ new Set(["id", "label", "index"]);
2613
+ const DUPLICATE_POLICIES = /* @__PURE__ */ new Set(["keep", "error", "first", "last", "sum", "min", "max"]);
2614
+ const SELF_LOOP_POLICIES = /* @__PURE__ */ new Set(["keep", "drop", "error"]);
2615
+ const IMPORT_MIXED_POLICIES = /* @__PURE__ */ new Set(["expand", "directed", "undirected", "error"]);
2616
+ const EXPORT_MIXED_POLICIES = /* @__PURE__ */ new Set(["error", "directed", "undirected"]);
2617
+ const WEIGHT_DTYPES = /* @__PURE__ */ new Set(["f32", "f64"]);
2618
+ const LONG_MODES = /* @__PURE__ */ new Set(["f64", "string"]);
2619
+ const HYPEREDGE_POLICIES = /* @__PURE__ */ new Set(["error", "skip", "star", "clique"]);
2620
+ const SANITIZE_MODES = /* @__PURE__ */ new Set(["error", "mangle"]);
2621
+ const DEFAULT_ERROR_LIMIT = 100;
2622
+ const SINK_OPTION_NAMES = ["addMissingNodes", "duplicateEdges", "selfLoops", "weightDtype"];
2623
+ function reportSinkOptions(sink, options, report, enforcesMissingNodes = false) {
2624
+ if (options === void 0) {
2625
+ return 0;
2626
+ }
2627
+ let recorded = 0;
2628
+ for (const name of SINK_OPTION_NAMES) {
2629
+ const wanted = options[name];
2630
+ const actual = sink.options[name];
2631
+ if (wanted === void 0 || wanted === actual) {
2632
+ continue;
2633
+ }
2634
+ if (name === "addMissingNodes" && enforcesMissingNodes && wanted === false) {
2635
+ continue;
2636
+ }
2637
+ report.warning(
2638
+ "coercion",
2639
+ SINK_OPTION_CODE,
2640
+ `option ${name}: ${JSON.stringify(wanted)} requested but the sink uses ${JSON.stringify(actual)}; the sink's setting applies`,
2641
+ { element: name }
2642
+ );
2643
+ recorded++;
2644
+ }
2645
+ return recorded;
2646
+ }
2647
+ const IGNORABLE_OPTION_NAMES = [
2648
+ "ids",
2649
+ "nodeIdFrom",
2650
+ "addMissingNodes",
2651
+ "duplicateEdges",
2652
+ "selfLoops",
2653
+ "onMixedDirection",
2654
+ "defaultDirected",
2655
+ "weightFrom",
2656
+ "weightDtype",
2657
+ "long",
2658
+ "restoreMangledIds",
2659
+ "hyperedges"
2660
+ ];
2661
+ const FIXED_DEFAULTS = {
2662
+ nodeIdFrom: "id",
2663
+ duplicateEdges: "keep",
2664
+ selfLoops: "keep",
2665
+ onMixedDirection: "expand",
2666
+ weightDtype: "f64",
2667
+ long: "f64",
2668
+ restoreMangledIds: true,
2669
+ hyperedges: "skip"
2670
+ };
2671
+ function reportUnusedOptions(options, report, used) {
2672
+ if (options === void 0) {
2673
+ return 0;
2674
+ }
2675
+ let recorded = 0;
2676
+ for (const name of IGNORABLE_OPTION_NAMES) {
2677
+ if (used.has(name) || SINK_OPTION_NAMES.includes(name)) {
2678
+ continue;
2679
+ }
2680
+ const value = options[name];
2681
+ if (value === void 0 || value === FIXED_DEFAULTS[name]) {
2682
+ continue;
2683
+ }
2684
+ report.warning(
2685
+ "unsupported",
2686
+ OPTION_IGNORED_CODE,
2687
+ `option ${name}: ${JSON.stringify(value)} has no effect on the ${report.format} importer`,
2688
+ { element: name }
2689
+ );
2690
+ recorded++;
2691
+ }
2692
+ return recorded;
2693
+ }
2694
+ function graphChosen(options) {
2695
+ return options?.graphIndex !== void 0 || options?.graphName !== void 0;
2696
+ }
2697
+ function graphNamesText(names) {
2698
+ const shown = names.slice(0, 10).map((n, i) => `${i} ${n === null ? "(unnamed)" : JSON.stringify(n)}`);
2699
+ const more = names.length > shown.length ? `, and ${names.length - shown.length} more` : "";
2700
+ return `; the file holds ${shown.join(", ")}${more}`;
2701
+ }
2702
+ function chooseGraph(names, options, report) {
2703
+ const { graphIndex, graphName } = options ?? {};
2704
+ if (graphIndex !== void 0 && (typeof graphIndex !== "number" || !Number.isInteger(graphIndex) || graphIndex < 0)) {
2705
+ throw new GraphFormatError(
2706
+ "E_UNSUPPORTED",
2707
+ `option graphIndex: ${describe(graphIndex)} is not a non-negative integer`,
2708
+ {
2709
+ option: "graphIndex",
2710
+ found: graphIndex
2711
+ }
2712
+ );
2713
+ }
2714
+ if (graphName !== void 0 && typeof graphName !== "string") {
2715
+ throw new GraphFormatError("E_UNSUPPORTED", `option graphName: ${describe(graphName)} is not a string`, {
2716
+ option: "graphName",
2717
+ found: graphName
2718
+ });
2719
+ }
2720
+ if (graphIndex !== void 0 && graphName !== void 0) {
2721
+ throw new GraphFormatError("E_UNSUPPORTED", "options graphIndex and graphName both choose a graph; pass one", {
2722
+ option: "graphName",
2723
+ found: graphName
2724
+ });
2725
+ }
2726
+ if (names.length === 0) {
2727
+ return report.fail(NO_GRAPH_CODE, "the input holds no graph");
2728
+ }
2729
+ if (graphName !== void 0) {
2730
+ const matches = names.flatMap((name, i) => name === graphName ? [i] : []);
2731
+ if (matches.length > 1) {
2732
+ return report.fail(
2733
+ AMBIGUOUS_GRAPH_NAME_CODE,
2734
+ `graphName ${JSON.stringify(graphName)} names the graphs at indexes ${matches.join(", ")}; pass graphIndex`,
2735
+ { element: graphName }
2736
+ );
2737
+ }
2738
+ if (matches.length === 0) {
2739
+ return report.fail(
2740
+ GRAPH_NOT_FOUND_CODE,
2741
+ `graphName ${JSON.stringify(graphName)} names none of the ${names.length} graph${plural(names.length)}${graphNamesText(names)}`,
2742
+ { element: graphName },
2743
+ { names: [...names] }
2744
+ );
2745
+ }
2746
+ return matches[0];
2747
+ }
2748
+ const index = graphIndex ?? 0;
2749
+ if (index >= names.length) {
2750
+ return report.fail(
2751
+ GRAPH_NOT_FOUND_CODE,
2752
+ `graphIndex ${index} is beyond the ${names.length} graph${plural(names.length)}${graphNamesText(names)}`
2753
+ );
2754
+ }
2755
+ return index;
2756
+ }
2757
+ function resolveImportOptions(options, defaults) {
2758
+ const o = options ?? {};
2759
+ return Object.freeze({
2760
+ ids: enumOption("ids", o.ids, defaults.ids, ID_COERCIONS),
2761
+ nodeIdFrom: enumOption("nodeIdFrom", o.nodeIdFrom, "id", NODE_ID_SOURCES),
2762
+ addMissingNodes: booleanOption("addMissingNodes", o.addMissingNodes, defaults.addMissingNodes ?? true),
2763
+ duplicateEdges: enumOption("duplicateEdges", o.duplicateEdges, "keep", DUPLICATE_POLICIES),
2764
+ selfLoops: enumOption("selfLoops", o.selfLoops, "keep", SELF_LOOP_POLICIES),
2765
+ onMixedDirection: enumOption("onMixedDirection", o.onMixedDirection, "expand", IMPORT_MIXED_POLICIES),
2766
+ defaultDirected: booleanOption("defaultDirected", o.defaultDirected, defaults.defaultDirected),
2767
+ weightFrom: weightFromOption(o.weightFrom, defaults.weightFrom),
2768
+ weightDtype: enumOption("weightDtype", o.weightDtype, "f64", WEIGHT_DTYPES),
2769
+ long: enumOption("long", o.long, "f64", LONG_MODES),
2770
+ restoreMangledIds: booleanOption("restoreMangledIds", o.restoreMangledIds, true),
2771
+ hyperedges: enumOption("hyperedges", o.hyperedges, "skip", HYPEREDGE_POLICIES),
2772
+ errorLimit: errorLimitOption(o.errorLimit),
2773
+ signal: signalOption(o.signal),
2774
+ onProgress: progressOption(o.onProgress),
2775
+ encoding: encodingOption(o.encoding)
2776
+ });
2777
+ }
2778
+ function resolveExportOptions(options) {
2779
+ const o = options ?? {};
2780
+ return Object.freeze({
2781
+ sanitizeIds: enumOption("sanitizeIds", o.sanitizeIds, "error", SANITIZE_MODES),
2782
+ onMixedDirection: enumOption("onMixedDirection", o.onMixedDirection, "error", EXPORT_MIXED_POLICIES)
2783
+ });
2784
+ }
2785
+ function enumOption(name, value, fallback, allowed) {
2786
+ if (value === void 0) {
2787
+ return fallback;
2788
+ }
2789
+ if (typeof value !== "string" || !allowed.has(value)) {
2790
+ throw new GraphFormatError(
2791
+ "E_UNSUPPORTED",
2792
+ `option ${name}: ${describe(value)} is not one of ${list(allowed)}`,
2793
+ {
2794
+ option: name,
2795
+ found: value,
2796
+ supported: [...allowed]
2797
+ }
2798
+ );
2799
+ }
2800
+ return value;
2801
+ }
2802
+ function booleanOption(name, value, fallback) {
2803
+ if (value === void 0) {
2804
+ return fallback;
2805
+ }
2806
+ if (typeof value !== "boolean") {
2807
+ throw new GraphFormatError("E_UNSUPPORTED", `option ${name}: ${describe(value)} is not a boolean`, {
2808
+ option: name,
2809
+ found: value
2810
+ });
2811
+ }
2812
+ return value;
2813
+ }
2814
+ function weightFromOption(value, fallback) {
2815
+ if (value === void 0) {
2816
+ return fallback;
2817
+ }
2818
+ if (value === null || typeof value === "string" && value.length > 0) {
2819
+ return value;
2820
+ }
2821
+ throw new GraphFormatError(
2822
+ "E_UNSUPPORTED",
2823
+ `option weightFrom: ${describe(value)} is not an attribute name or null`,
2824
+ { option: "weightFrom", found: value }
2825
+ );
2826
+ }
2827
+ function errorLimitOption(value) {
2828
+ if (value === void 0) {
2829
+ return DEFAULT_ERROR_LIMIT;
2830
+ }
2831
+ if (typeof value === "number" && value >= 0 && (Number.isInteger(value) || value === Infinity)) {
2832
+ return value;
2833
+ }
2834
+ throw new GraphFormatError(
2835
+ "E_UNSUPPORTED",
2836
+ `option errorLimit: ${describe(value)} is not a non-negative integer or Infinity`,
2837
+ { option: "errorLimit", found: value }
2838
+ );
2839
+ }
2840
+ function signalOption(value) {
2841
+ if (value === void 0 || value === null) {
2842
+ return null;
2843
+ }
2844
+ if (typeof value === "object" && typeof value.aborted === "boolean") {
2845
+ return value;
2846
+ }
2847
+ throw new GraphFormatError("E_UNSUPPORTED", `option signal: ${describe(value)} is not an AbortSignal`, {
2848
+ option: "signal",
2849
+ found: typeof value
2850
+ });
2851
+ }
2852
+ function progressOption(value) {
2853
+ if (value === void 0 || value === null) {
2854
+ return null;
2855
+ }
2856
+ if (typeof value === "function") {
2857
+ return value;
2858
+ }
2859
+ throw new GraphFormatError("E_UNSUPPORTED", `option onProgress: ${describe(value)} is not a function`, {
2860
+ option: "onProgress",
2861
+ found: typeof value
2862
+ });
2863
+ }
2864
+ function encodingOption(value) {
2865
+ if (value === void 0 || value === null) {
2866
+ return null;
2867
+ }
2868
+ const canonical = typeof value === "string" ? canonicalEncoding(value) : null;
2869
+ if (canonical === null) {
2870
+ throw new GraphFormatError(
2871
+ "E_UNSUPPORTED",
2872
+ `option encoding: ${describe(value)} is not an encoding this platform's TextDecoder knows`,
2873
+ { option: "encoding", found: value }
2874
+ );
2875
+ }
2876
+ return canonical;
2877
+ }
2878
+ function forDecodedText(options) {
2879
+ return { ...options, encoding: void 0, onProgress: void 0 };
2880
+ }
2881
+ const FORMAT_DIALECTS = Object.freeze({
2882
+ csv: Object.freeze(["gephi", "generic"]),
2883
+ json: Object.freeze(["node-link", "d3", "jgf", "cytoscape", "graphology", "vis", "obographs"])
2884
+ });
2885
+ function otherFormatDialect(format, value) {
2886
+ return typeof value === "string" && Object.entries(FORMAT_DIALECTS).some(([f, names]) => f !== format && names.includes(value));
2887
+ }
2888
+ function describe(value) {
2889
+ switch (typeof value) {
2890
+ case "string":
2891
+ return JSON.stringify(value);
2892
+ case "number":
2893
+ case "boolean":
2894
+ return String(value);
2895
+ default:
2896
+ return value === null ? "null" : typeof value;
2897
+ }
2898
+ }
2899
+ function list(allowed) {
2900
+ return [...allowed].map((v) => JSON.stringify(v)).join(", ");
2901
+ }
2902
+ class ImportError extends GraphFormatError {
2903
+ /**
2904
+ * Create an ImportError.
2905
+ * @param message - a plain-ASCII human-readable message
2906
+ * @param report - the partial report
2907
+ * @param details - optional machine-readable context; its `code` names the issue that stopped the import
2908
+ */
2909
+ constructor(message, report, details) {
2910
+ super("E_IMPORT", message, details);
2911
+ this.name = "ImportError";
2912
+ Object.defineProperty(this, "report", { value: report, enumerable: false });
2913
+ this.issue = stoppingIssue(report.issues, details?.code);
2914
+ }
2915
+ }
2916
+ function stoppingIssue(issues, code) {
2917
+ let lastError = null;
2918
+ for (let i = issues.length - 1; i >= 0; i--) {
2919
+ if (issues[i].code === code) {
2920
+ return issues[i];
2921
+ }
2922
+ if (lastError === null && issues[i].severity === "error") {
2923
+ lastError = issues[i];
2924
+ }
2925
+ }
2926
+ return lastError;
2927
+ }
2928
+ const MAX_WARNINGS_PER_CODE = 1e3;
2929
+ const CATEGORY_BY_CODE = {
2930
+ E_UNKNOWN_NODE: "missing-value",
2931
+ E_UNKNOWN_COLUMN: "missing-value",
2932
+ E_DIRECTED: "coercion",
2933
+ E_TOO_LARGE: "unsupported",
2934
+ E_UNSUPPORTED: "unsupported",
2935
+ E_GPU_INELIGIBLE: "unsupported"
2936
+ };
2937
+ const PARSE_ERROR_CODE = "E_PARSE";
2938
+ function withLine(message, where) {
2939
+ const line = where?.line;
2940
+ return line === void 0 || line === null || message.includes(`line ${line}`) ? message : `line ${line}: ${message}`;
2941
+ }
2942
+ class ImportReportBuilder {
2943
+ /**
2944
+ * Create a builder for one import call.
2945
+ * @param format - the importer's format name
2946
+ * @param errorLimit - errors tolerated before the import aborts; Infinity for no limit
2947
+ */
2948
+ constructor(format, errorLimit) {
2949
+ this.counts = { nodes: 0, edges: 0, skippedNodes: 0, skippedEdges: 0, expandedMixed: 0 };
2950
+ this.issueList = [];
2951
+ this.lossList = [];
2952
+ this.onceCodes = /* @__PURE__ */ new Set();
2953
+ this.warningsByCode = /* @__PURE__ */ new Map();
2954
+ this.errors = 0;
2955
+ this.warnings = 0;
2956
+ this.truncatedFlag = false;
2957
+ this.format = format;
2958
+ this.errorLimit = errorLimit;
2959
+ this.startedAt = now();
2960
+ }
2961
+ /**
2962
+ * Issues recorded so far, in order.
2963
+ * @returns the live list (not copied; finish() copies)
2964
+ */
2965
+ get issues() {
2966
+ return this.issueList;
2967
+ }
2968
+ /**
2969
+ * Issues with severity "error".
2970
+ * @returns the count
2971
+ */
2972
+ get errorCount() {
2973
+ return this.errors;
2974
+ }
2975
+ /**
2976
+ * Issues with severity "warning".
2977
+ * @returns the count
2978
+ */
2979
+ get warningCount() {
2980
+ return this.warnings;
2981
+ }
2982
+ /**
2983
+ * Whether the error limit was exceeded.
2984
+ * @returns true once an error beyond the limit was recorded
2985
+ */
2986
+ get truncated() {
2987
+ return this.truncatedFlag;
2988
+ }
2989
+ /**
2990
+ * Loss notes recorded so far.
2991
+ * @returns the live list
2992
+ */
2993
+ get lossy() {
2994
+ return this.lossList;
2995
+ }
2996
+ /**
2997
+ * Record an error. When the count goes beyond the error limit the report is marked truncated
2998
+ * and an ImportError carrying it is thrown; the importer does not catch that.
2999
+ * @param category - the issue category
3000
+ * @param code - a stable code such as "E_UNKNOWN_NODE"
3001
+ * @param message - a plain-ASCII message
3002
+ * @param where - the line and element, when known
3003
+ * @returns the recorded issue
3004
+ */
3005
+ error(category, code, message, where) {
3006
+ const issue = makeIssue(category, "error", code, message, where);
3007
+ this.issueList.push(issue);
3008
+ this.errors++;
3009
+ if (this.errors > this.errorLimit) {
3010
+ this.truncatedFlag = true;
3011
+ throw this.abort(`error limit of ${this.errorLimit} exceeded: ${withLine(message, where)}`, {
3012
+ code,
3013
+ limit: this.errorLimit
3014
+ });
3015
+ }
3016
+ return issue;
3017
+ }
3018
+ /**
3019
+ * Record a warning; warnings never count toward the limit. Beyond MAX_WARNINGS_PER_CODE
3020
+ * warnings of one code the warning is counted, not kept: finish() adds one W_ISSUES_SUPPRESSED
3021
+ * warning per such code with the number dropped.
3022
+ * @param category - the issue category
3023
+ * @param code - a stable code such as "W_WIDENED"
3024
+ * @param message - a plain-ASCII message
3025
+ * @param where - the line and element, when known
3026
+ * @returns the recorded issue
3027
+ */
3028
+ warning(category, code, message, where) {
3029
+ const issue = makeIssue(category, "warning", code, message, where);
3030
+ const seen = (this.warningsByCode.get(code) ?? 0) + 1;
3031
+ this.warningsByCode.set(code, seen);
3032
+ if (seen <= MAX_WARNINGS_PER_CODE) {
3033
+ this.issueList.push(issue);
3034
+ this.warnings++;
3035
+ }
3036
+ return issue;
3037
+ }
3038
+ /**
3039
+ * Record a warning the first time its key is seen and ignore later repeats, for conditions
3040
+ * that would otherwise produce one warning per row.
3041
+ * @param category - the issue category
3042
+ * @param code - the stable code
3043
+ * @param message - a plain-ASCII message
3044
+ * @param where - the line and element, when known
3045
+ * @param key - what repeats are deduplicated on; the code itself by default (pass `code:column`
3046
+ * to warn once per column)
3047
+ * @returns the recorded issue, or null when the key was already recorded
3048
+ */
3049
+ warnOnce(category, code, message, where, key = code) {
3050
+ if (this.onceCodes.has(key)) {
3051
+ return null;
3052
+ }
3053
+ this.onceCodes.add(key);
3054
+ return this.warning(category, code, message, where);
3055
+ }
3056
+ /**
3057
+ * Record something the importer could not represent.
3058
+ * @param code - a stable code
3059
+ * @param message - a plain-ASCII message
3060
+ * @param column - the affected column, or null
3061
+ * @param count - the affected count, or null
3062
+ * @returns the recorded note
3063
+ */
3064
+ loss(code, message, column = null, count = null) {
3065
+ const note = Object.freeze({ code, message, column, count });
3066
+ this.lossList.push(note);
3067
+ return note;
3068
+ }
3069
+ /**
3070
+ * The per-element catch: record a thrown GraphFormatError as an error
3071
+ * issue with its code and the category the code implies. Anything else is re-thrown unchanged:
3072
+ * an ImportError (the import already aborted), an abort reason, and any other thrown value (a
3073
+ * TypeError or RangeError is a programming error in the importer or the sink, never a defect of
3074
+ * the input, so it must surface as an exception rather than as an issue blamed on the file).
3075
+ * @param err - the thrown value
3076
+ * @param where - the line and element, when known
3077
+ * @returns the recorded issue
3078
+ */
3079
+ recordError(err, where) {
3080
+ if (err instanceof GraphFormatError && !(err instanceof ImportError)) {
3081
+ const category = CATEGORY_BY_CODE[err.code] ?? "validation-error";
3082
+ if (err.code === "E_TOO_LARGE") {
3083
+ return this.failWith(category, err.code, err.message, where);
3084
+ }
3085
+ return this.error(category, err.code, err.message, where);
3086
+ }
3087
+ throw err;
3088
+ }
3089
+ /**
3090
+ * A builder that starts from everything this one recorded so far: issues, counts, loss notes,
3091
+ * the warnOnce keys, the error and warning counts and the truncation flag. For an importer that
3092
+ * reads its input once and emits several graphs, each with its own report.
3093
+ * @returns the copy; later records to either builder do not reach the other
3094
+ */
3095
+ fork() {
3096
+ const copy = new ImportReportBuilder(this.format, this.errorLimit);
3097
+ Object.assign(copy.counts, this.counts);
3098
+ copy.issueList.push(...this.issueList);
3099
+ copy.lossList.push(...this.lossList);
3100
+ for (const key of this.onceCodes) {
3101
+ copy.onceCodes.add(key);
3102
+ }
3103
+ for (const [code, count] of this.warningsByCode) {
3104
+ copy.warningsByCode.set(code, count);
3105
+ }
3106
+ copy.errors = this.errors;
3107
+ copy.warnings = this.warnings;
3108
+ copy.truncatedFlag = this.truncatedFlag;
3109
+ return copy;
3110
+ }
3111
+ /**
3112
+ * Build the ImportError that aborts the import, carrying the report so far. The caller throws
3113
+ * it; this method only constructs it so it can be used in expression position.
3114
+ * @param message - a plain-ASCII message
3115
+ * @param details - optional machine-readable context
3116
+ * @returns the error to throw
3117
+ */
3118
+ abort(message, details) {
3119
+ return new ImportError(message, this.finish(), details);
3120
+ }
3121
+ /**
3122
+ * Record a fatal parse error and abort: the issue is recorded (even beyond the error limit)
3123
+ * and an ImportError carrying the report is thrown.
3124
+ * @param code - a stable code such as "E_INVALID_UTF8"
3125
+ * @param message - a plain-ASCII message
3126
+ * @param where - the line and element, when known
3127
+ * @param details - optional machine-readable context for the ImportError
3128
+ */
3129
+ fail(code, message, where, details) {
3130
+ this.failWith("parse-error", code, message, where, details);
3131
+ }
3132
+ /**
3133
+ * Record a fatal error of any category and abort, as fail() does for a parse error: a size
3134
+ * limit (E_TOO_LARGE, category "unsupported") stops an import without being a defect of the
3135
+ * syntax. A fatal error is not the error limit: `truncated` stays as it was.
3136
+ * @param category - the issue category
3137
+ * @param code - a stable code
3138
+ * @param message - a plain-ASCII message
3139
+ * @param where - the line and element, when known
3140
+ * @param details - optional machine-readable context for the ImportError
3141
+ */
3142
+ failWith(category, code, message, where, details) {
3143
+ this.issueList.push(makeIssue(category, "error", code, message, where));
3144
+ this.errors++;
3145
+ throw this.abort(withLine(message, where), { code, ...details });
3146
+ }
3147
+ /**
3148
+ * Add a finished report to this one: its issues after the ones recorded so far, its counts, its
3149
+ * loss notes and its truncated flag. Use it when an importer hands part of the work to another
3150
+ * importer (for example, a wrapper around the CSV importer) and returns one report for both. The issues
3151
+ * keep their codes; errors added this way do not count toward this report's error limit, since
3152
+ * the other importer applied its own.
3153
+ * @param report - the report the other importer returned
3154
+ * @returns this builder
3155
+ * @example
3156
+ * ```ts
3157
+ * const report = new ImportReportBuilder("netscope", opts.errorLimit);
3158
+ * const text = await readText(input, report, opts);
3159
+ * report.include(await csvImporter.import(text, sink, options));
3160
+ * return report.finish();
3161
+ * ```
3162
+ */
3163
+ include(report) {
3164
+ for (const issue of report.issues) {
3165
+ this.issueList.push(issue);
3166
+ if (issue.severity === "error") {
3167
+ this.errors++;
3168
+ } else {
3169
+ this.warnings++;
3170
+ }
3171
+ }
3172
+ const { counts } = report;
3173
+ this.counts.nodes += counts.nodes;
3174
+ this.counts.edges += counts.edges;
3175
+ this.counts.skippedNodes += counts.skippedNodes;
3176
+ this.counts.skippedEdges += counts.skippedEdges;
3177
+ this.counts.expandedMixed += counts.expandedMixed;
3178
+ this.lossList.push(...report.lossy);
3179
+ this.truncatedFlag ||= report.truncated;
3180
+ return this;
3181
+ }
3182
+ /**
3183
+ * The report as it stands: a frozen snapshot with the parse duration so far. Can be called more
3184
+ * than once; each call reflects everything recorded up to that point.
3185
+ * @returns the report
3186
+ */
3187
+ finish() {
3188
+ const { nodes, edges, skippedNodes, skippedEdges, expandedMixed } = this.counts;
3189
+ const suppressed = [];
3190
+ for (const [code, seen] of this.warningsByCode) {
3191
+ if (seen > MAX_WARNINGS_PER_CODE) {
3192
+ const more = seen - MAX_WARNINGS_PER_CODE;
3193
+ suppressed.push(
3194
+ makeIssue(
3195
+ "unsupported",
3196
+ "warning",
3197
+ ISSUES_SUPPRESSED_CODE,
3198
+ `${more} more ${code} warning${plural(more)} ${agree(more, "was", "were")} not kept (the report keeps the first ${MAX_WARNINGS_PER_CODE})`,
3199
+ { element: code }
3200
+ )
3201
+ );
3202
+ }
3203
+ }
3204
+ return Object.freeze({
3205
+ format: this.format,
3206
+ counts: Object.freeze({ nodes, edges, skippedNodes, skippedEdges, expandedMixed }),
3207
+ issues: Object.freeze([...this.issueList, ...suppressed]),
3208
+ errorCount: this.errors,
3209
+ warningCount: this.warnings + suppressed.length,
3210
+ truncated: this.truncatedFlag,
3211
+ lossy: Object.freeze([...this.lossList]),
3212
+ durationMs: now() - this.startedAt
3213
+ });
3214
+ }
3215
+ }
3216
+ function makeIssue(category, severity, code, message, where) {
3217
+ return Object.freeze({
3218
+ category,
3219
+ severity,
3220
+ code,
3221
+ message,
3222
+ line: where?.line ?? null,
3223
+ element: where?.element ?? null
3224
+ });
3225
+ }
3226
+ function isAbortError(err) {
3227
+ if (typeof err !== "object" || err === null) {
3228
+ return false;
3229
+ }
3230
+ const { name } = err;
3231
+ return name === "AbortError" || name === "TimeoutError";
3232
+ }
3233
+ function messageOf(err) {
3234
+ if (err instanceof Error) {
3235
+ return err.message;
3236
+ }
3237
+ if (typeof err === "string") {
3238
+ return err;
3239
+ }
3240
+ return `non-error thrown (${typeof err})`;
3241
+ }
3242
+ function now() {
3243
+ return typeof performance === "object" ? performance.now() : Date.now();
3244
+ }
3245
+ function formatF32(value) {
3246
+ if (!Number.isFinite(value)) {
3247
+ return String(value);
3248
+ }
3249
+ if (value === 0) {
3250
+ return Object.is(value, -0) ? "-0" : "0";
3251
+ }
3252
+ for (let digits = 1; digits <= 9; digits++) {
3253
+ const text = value.toPrecision(digits);
3254
+ if (Math.fround(Number(text)) === value) {
3255
+ return String(Number(text));
3256
+ }
3257
+ }
3258
+ return String(value);
3259
+ }
3260
+ function survivesF32(value) {
3261
+ return Number(formatF32(Math.fround(value))) === value;
3262
+ }
3263
+ function formatF64(value) {
3264
+ return Object.is(value, -0) ? "-0" : String(value);
3265
+ }
3266
+ function idText(id) {
3267
+ return typeof id === "number" ? formatF64(id) : id;
3268
+ }
3269
+ function formatDecimal(value, dtype = "f64") {
3270
+ if (!Number.isFinite(value)) {
3271
+ return String(value);
3272
+ }
3273
+ if (Object.is(value, -0)) {
3274
+ return "-0.0";
3275
+ }
3276
+ const text = formatNumber(value, dtype);
3277
+ return text.includes(".") || text.includes("e") ? text : `${text}.0`;
3278
+ }
3279
+ function formatGmlReal(value, dtype = "f64") {
3280
+ if (Number.isNaN(value)) {
3281
+ return "NAN";
3282
+ }
3283
+ if (!Number.isFinite(value)) {
3284
+ return value > 0 ? "+INF" : "-INF";
3285
+ }
3286
+ const text = formatDecimal(value, dtype);
3287
+ if (text.includes(".")) {
3288
+ return text;
3289
+ }
3290
+ const e = text.indexOf("e");
3291
+ return `${text.slice(0, e)}.0${text.slice(e)}`;
3292
+ }
3293
+ function formatInteger(value) {
3294
+ if (Number.isSafeInteger(value) || !Number.isFinite(value)) {
3295
+ return String(value);
3296
+ }
3297
+ return BigInt(value).toString();
3298
+ }
3299
+ function formatNumber(value, dtype) {
3300
+ return dtype === "f32" ? formatF32(value) : formatF64(value);
3301
+ }
3302
+ const DEFAULT_WEIGHT = 1;
3303
+ function isWeightField(name, weightFrom) {
3304
+ return weightFrom !== null && name === weightFrom;
3305
+ }
3306
+ function parseWeightText(text, report) {
3307
+ const trimmed = text.trim();
3308
+ if (trimmed.length === 0) {
3309
+ return void 0;
3310
+ }
3311
+ let value;
3312
+ try {
3313
+ value = parseDecimalText(trimmed);
3314
+ } catch (err) {
3315
+ throw invalidWeight(text, err);
3316
+ }
3317
+ if (Number.isNaN(value)) {
3318
+ throw invalidWeight(text, null);
3319
+ }
3320
+ if (report !== void 0) {
3321
+ reportWeightPrecision(trimmed, value, report);
3322
+ }
3323
+ return value;
3324
+ }
3325
+ function reportWeightPrecision(text, value, report) {
3326
+ if (!Number.isSafeInteger(value) && Number.isFinite(value) && /^[+-]?\d+$/.test(text) && BigInt(text) !== BigInt(value)) {
3327
+ report.warnOnce(
3328
+ "precision",
3329
+ PRECISION_CODE,
3330
+ `edge weights: integers beyond 2^53 are stored as the nearest double (first: ${text})`,
3331
+ void 0,
3332
+ `${PRECISION_CODE}:edge weight`
3333
+ );
3334
+ }
3335
+ }
3336
+ function weightFromValue(value) {
3337
+ if (value === void 0 || value === null) {
3338
+ return void 0;
3339
+ }
3340
+ if (typeof value === "number") {
3341
+ if (Number.isNaN(value)) {
3342
+ throw invalidWeight(value, null);
3343
+ }
3344
+ return value;
3345
+ }
3346
+ if (typeof value === "string") {
3347
+ return parseWeightText(value);
3348
+ }
3349
+ throw invalidWeight(value, null);
3350
+ }
3351
+ function invalidWeight(value, cause) {
3352
+ let shown;
3353
+ switch (typeof value) {
3354
+ case "string":
3355
+ shown = JSON.stringify(value);
3356
+ break;
3357
+ case "number":
3358
+ shown = String(value);
3359
+ break;
3360
+ default:
3361
+ shown = typeof value;
3362
+ }
3363
+ return new GraphFormatError("E_INVALID_WEIGHT", `invalid edge weight ${shown}`, {
3364
+ value: typeof value === "object" ? typeof value : value,
3365
+ cause: cause instanceof Error ? cause.message : null
3366
+ });
3367
+ }
3368
+ const NEGATIVE_ZERO_TEXT = "-0";
3369
+ const NUMERIC_DTYPES = /* @__PURE__ */ new Set(["f32", "f64", "i32", "u32", "u8"]);
3370
+ function weightFormatter(dtype) {
3371
+ switch (dtype) {
3372
+ case "f32":
3373
+ return formatF32;
3374
+ case "f64":
3375
+ return formatF64;
3376
+ default:
3377
+ return formatInteger;
3378
+ }
3379
+ }
3380
+ function explicitWeights(snapshot) {
3381
+ const shadowColumn = snapshot.edges.byRole("weight");
3382
+ const shadow = shadowColumn !== null && NUMERIC_DTYPES.has(shadowColumn.dtype) ? shadowColumn : null;
3383
+ if (shadow !== null) {
3384
+ const dtype = shadow.dtype === "f32" ? "f32" : "f64";
3385
+ const format = weightFormatter(shadow.dtype);
3386
+ return {
3387
+ weighted: true,
3388
+ dtype,
3389
+ isExplicit: (e) => shadow.isSet(e),
3390
+ value: (e) => shadow.value(e),
3391
+ text: (e, integral = false) => {
3392
+ if (!shadow.isSet(e)) {
3393
+ return null;
3394
+ }
3395
+ const value = shadow.value(e);
3396
+ if (Object.is(value, -0)) {
3397
+ return NEGATIVE_ZERO_TEXT;
3398
+ }
3399
+ return integral && Number.isInteger(value) ? formatInteger(value) : format(value);
3400
+ }
3401
+ };
3402
+ }
3403
+ const { weights } = snapshot.edgeList();
3404
+ if (weights === null || !snapshot.flags.weighted) {
3405
+ return {
3406
+ weighted: false,
3407
+ dtype: "f32",
3408
+ isExplicit: () => false,
3409
+ value: () => DEFAULT_WEIGHT,
3410
+ text: () => null
3411
+ };
3412
+ }
3413
+ return {
3414
+ weighted: true,
3415
+ dtype: "f32",
3416
+ isExplicit: () => true,
3417
+ value: (e) => weights[e],
3418
+ text: (e, integral = false) => {
3419
+ const value = weights[e];
3420
+ if (Object.is(value, -0)) {
3421
+ return NEGATIVE_ZERO_TEXT;
3422
+ }
3423
+ return integral && Number.isInteger(value) ? formatInteger(value) : formatF32(value);
3424
+ }
3425
+ };
3426
+ }
3427
+ function edgeWeights(snapshot) {
3428
+ const { weights } = snapshot.edgeList();
3429
+ if (weights === null) {
3430
+ return null;
3431
+ }
3432
+ const out = Float64Array.from(weights);
3433
+ const exact = snapshot.edges.byRole("weight");
3434
+ if (exact !== null) {
3435
+ for (let e = 0; e < out.length; e++) {
3436
+ const v = exact.value(e);
3437
+ if (typeof v === "number") {
3438
+ out[e] = v;
3439
+ }
3440
+ }
3441
+ }
3442
+ return out;
3443
+ }
3444
+ const ID_CHARSET_REFUSAL = "E_ID_CHARSET";
3445
+ const LOSS = Object.freeze({
3446
+ /**
3447
+ * A node or edge attribute is not written: the format has no attributes, or none of this kind
3448
+ * (`CheckExtras.attributes` false).
3449
+ */
3450
+ COLUMN_DROPPED: COLUMN_DROPPED_CODE,
3451
+ /**
3452
+ * The graph has both directed and undirected edges, the format holds one direction per file, and
3453
+ * `onMixedDirection` is "directed" or "undirected": every edge is written with that direction.
3454
+ */
3455
+ MIXED_DIRECTION: "W_MIXED_DIRECTION",
3456
+ /**
3457
+ * The graph has both directed and undirected edges and `onMixedDirection` is "error". An import stops; a save to a
3458
+ * format that holds one direction per file fails with E_DIRECTED. Pass "directed" or "undirected" to read or write
3459
+ * it anyway.
3460
+ */
3461
+ MIXED_DIRECTION_ERROR: MIXED_DIRECTION_CODE,
3462
+ /** Parallel edges in a format without them. */
3463
+ MULTI_EDGES: "W_MULTI_EDGES",
3464
+ /** Self-loops in a format without them. */
3465
+ SELF_LOOPS: "W_SELF_LOOPS",
3466
+ /**
3467
+ * The format needs an id on every edge and the graph has none, so the file gets ids e0, e1, e2 and so on, which
3468
+ * read back as edge ids.
3469
+ */
3470
+ EDGE_IDS_GENERATED: "W_EDGE_IDS_GENERATED",
3471
+ /** The graph has edge ids and the format has no place for them, so they are not written. */
3472
+ EDGE_IDS_DROPPED: "W_EDGE_IDS_DROPPED",
3473
+ /** Ids outside the format's charset are rewritten (sanitizeIds "mangle"). */
3474
+ ID_MANGLED: "W_ID_MANGLED",
3475
+ /**
3476
+ * Node ids the format cannot write, under `sanitizeIds: "error"`; the save fails with E_INVALID_ID. Pass
3477
+ * `sanitizeIds: "mangle"` to rewrite them.
3478
+ */
3479
+ ID_CHARSET: ID_CHARSET_REFUSAL,
3480
+ /** The format numbers nodes 1..N; ids that are not their 1-based index are kept as labels only. */
3481
+ ID_RENUMBERED: "W_ID_RENUMBERED",
3482
+ /**
3483
+ * An attribute's type is one the format cannot store as it is (for example, a 32-bit float in a format that has only 64-bit
3484
+ * numbers), so it reads back with the nearest type the format has.
3485
+ */
3486
+ DTYPE: "W_DTYPE_UNSUPPORTED",
3487
+ /**
3488
+ * An attribute with several numbers per element (other than a position) is written as separate values or a list,
3489
+ * and does not read back as one attribute.
3490
+ */
3491
+ COMPONENTS: "W_COMPONENTS_FLATTENED",
3492
+ /** A list column in a format without lists. */
3493
+ LIST: "W_LIST_UNSUPPORTED",
3494
+ /** A json column in a format without nested values. */
3495
+ JSON: "W_JSON_UNSUPPORTED",
3496
+ /** A declared default in a format without defaults. */
3497
+ DEFAULT: "W_DEFAULT_DROPPED",
3498
+ /** Declared options in a format without enumerations. */
3499
+ OPTIONS: "W_OPTIONS_DROPPED",
3500
+ /** A parent / parents column in a format without containment. */
3501
+ HIERARCHY: "W_HIERARCHY_DROPPED",
3502
+ /** A start / end / timestamp column in a format without temporal support. */
3503
+ TEMPORAL: TEMPORAL_DROPPED_CODE,
3504
+ /** A `<column>.text` companion the format cannot carry. */
3505
+ TEMPORAL_TEXT: TEMPORAL_TEXT_DROPPED_CODE,
3506
+ /** An attribute with a role the format has no place for is written as a plain attribute; the role is lost. */
3507
+ ROLE: ROLE_DROPPED_CODE,
3508
+ /** A parents (multi-parent) column in a format with single containment only. */
3509
+ PARENTS: PARENTS_DROPPED_CODE,
3510
+ /** A mutual pair written as two directed edges without the mutual mark. */
3511
+ MUTUAL_EXPANDED: MUTUAL_EXPANDED_CODE,
3512
+ /** A mutual pair written as one undirected edge; the mark is lost and the pair reads back undirected. */
3513
+ MUTUAL_AS_UNDIRECTED: MUTUAL_AS_UNDIRECTED_CODE,
3514
+ /** Node ids whose written text reads back as the other type under the importer's id rule. */
3515
+ ID_TEXT_TYPE: ID_TEXT_TYPE_CODE,
3516
+ /**
3517
+ * Two node ids would be written as the same text (the number 5 and the text "5"); the save fails with
3518
+ * E_INVALID_ID.
3519
+ */
3520
+ ID_TEXT_COLLISION: ID_TEXT_COLLISION_CODE,
3521
+ /**
3522
+ * An attribute without the weight role is named like the attribute graph-io reads weights from (for example, `weight`), so
3523
+ * it reads back as the edge weight.
3524
+ */
3525
+ WEIGHT_KEY_CLASH: WEIGHT_KEY_CLASH_CODE,
3526
+ /**
3527
+ * An attribute without a role is written where the format keeps a role (for example, a `name` column as the label), and
3528
+ * reads back with that role.
3529
+ */
3530
+ ROLE_ASSUMED: ROLE_ASSUMED_CODE,
3531
+ /**
3532
+ * An attribute with a role (for example, the label) is written where the format keeps that role, and reads back under the
3533
+ * name the format's importer gives it.
3534
+ */
3535
+ COLUMN_NAME_CHANGED: COLUMN_RENAMED_LOSS_CODE,
3536
+ /** A declared column whose every row is unset vanishes through a format without declarations. */
3537
+ EMPTY_COLUMN: EMPTY_COLUMN_DROPPED_CODE,
3538
+ /**
3539
+ * A text attribute reads back as a dictionary attribute, or the reverse, because the importer chooses by how often
3540
+ * its values repeat. The values are the same.
3541
+ */
3542
+ STORAGE_CLASS: STORAGE_CLASS_CODE,
3543
+ /**
3544
+ * A number attribute whose values are all whole numbers reads back as integers, because the format does not record
3545
+ * the type.
3546
+ */
3547
+ INTEGRAL_F64: INTEGRAL_F64_CODE,
3548
+ /**
3549
+ * A text value that reads back as a number or a boolean, because the format does not record that it was text (the
3550
+ * text "42" reads back as the number 42).
3551
+ */
3552
+ TEXT_INFERRED: TEXT_INFERRED_CODE,
3553
+ /** A text value holds a character XML 1.0 forbids (most control characters); the save fails with E_COLUMN_TYPE. */
3554
+ XML_ILLEGAL_CHAR: XML_ILLEGAL_CHAR_CODE,
3555
+ /**
3556
+ * A text attribute stored as a dictionary, without a declared list of allowed values, reads back with its distinct
3557
+ * values as that list.
3558
+ */
3559
+ OPTIONS_GAINED: OPTIONS_GAINED_CODE,
3560
+ /** A spells column in a format without spells. */
3561
+ SPELLS: "W_SPELLS_DROPPED",
3562
+ /** Dynamic attribute values (extension tables) in a format without them. */
3563
+ DYNAMIC_VALUES: "W_DYNAMIC_VALUES_DROPPED",
3564
+ /** An open-interval column in a format without open intervals. */
3565
+ OPEN_INTERVAL: "W_OPEN_INTERVAL",
3566
+ /** Graph-level attributes in a format without them. */
3567
+ GRAPH_ATTRIBUTES: "W_GRAPH_ATTRIBUTES_DROPPED",
3568
+ /** A position column in a format without positions. */
3569
+ POSITIONS: "W_POSITIONS_DROPPED",
3570
+ /** Visual columns in a format without them. */
3571
+ VIZ: "W_VIZ_DROPPED",
3572
+ /** An extension table the format cannot carry. */
3573
+ EXTENSION_TABLE: "W_EXTENSION_TABLE_DROPPED",
3574
+ /** A NaN or infinite number the format cannot spell; not written (or written as null), it reads back unset. */
3575
+ NONFINITE_AS_NULL: NONFINITE_AS_NULL_CODE,
3576
+ /**
3577
+ * The graph has edge weights and the file does not keep them (the format has no weights, or an option turned them
3578
+ * off): every edge reads back with the default weight 1.
3579
+ */
3580
+ WEIGHTS_DROPPED: WEIGHTS_DROPPED_CODE
3581
+ });
3582
+ function refusedSave(notes, codes = {}) {
3583
+ const note = notes.find((n) => n.code.startsWith("E_"));
3584
+ if (note === void 0) {
3585
+ return null;
3586
+ }
3587
+ const code = codes[note.code] ?? REFUSAL_CODES[note.code] ?? "E_UNSUPPORTED";
3588
+ return new GraphFormatError(code, note.message, { code: note.code, column: note.column, count: note.count });
3589
+ }
3590
+ const REFUSAL_CODES = {
3591
+ [ID_CHARSET_REFUSAL]: "E_INVALID_ID",
3592
+ [ID_TEXT_COLLISION_CODE]: "E_INVALID_ID",
3593
+ [MIXED_DIRECTION_CODE]: "E_DIRECTED",
3594
+ [XML_ILLEGAL_CHAR_CODE]: "E_COLUMN_TYPE"
3595
+ };
3596
+ const NO_CAPABILITIES = Object.freeze({
3597
+ mixedDirection: false,
3598
+ multiEdges: false,
3599
+ selfLoops: false,
3600
+ edgeIds: "none",
3601
+ idCharset: "any",
3602
+ dtypes: Object.freeze([]),
3603
+ components: false,
3604
+ lists: false,
3605
+ json: false,
3606
+ defaults: false,
3607
+ options: false,
3608
+ hierarchy: false,
3609
+ temporal: "none",
3610
+ graphAttributes: false,
3611
+ positions: false,
3612
+ viz: false
3613
+ });
3614
+ function capabilities(supported) {
3615
+ return Object.freeze({ ...NO_CAPABILITIES, ...supported, dtypes: Object.freeze([...supported.dtypes ?? []]) });
3616
+ }
3617
+ const STRUCTURAL_ROLES = /* @__PURE__ */ new Set(["directed", "pair", "mutual", "weight", "originalId"]);
3618
+ const VIZ_ROLES = /* @__PURE__ */ new Set(["color", "size", "shape", "thickness"]);
3619
+ const TEMPORAL_ROLES = /* @__PURE__ */ new Set(["start", "end", "timestamp", "timestamps"]);
3620
+ const HIERARCHY_ROLES = /* @__PURE__ */ new Set(["parent", "parents"]);
3621
+ function checkCapabilities(snapshot, caps, options, extras = {}) {
3622
+ const notes = [];
3623
+ const note = (code, message, column = null, count = null) => {
3624
+ notes.push(Object.freeze({ code, message, column, count }));
3625
+ };
3626
+ const mixed = countMixedEdges(snapshot);
3627
+ if (mixed > 0 && !caps.mixedDirection) {
3628
+ if (options.onMixedDirection === "error") {
3629
+ note(
3630
+ LOSS.MIXED_DIRECTION_ERROR,
3631
+ `${mixed} undirected edge${plural(mixed)} in a directed graph, and the format holds one direction per file, so the save fails unless onMixedDirection is "directed" or "undirected"`,
3632
+ null,
3633
+ mixed
3634
+ );
3635
+ } else {
3636
+ note(
3637
+ LOSS.MIXED_DIRECTION,
3638
+ `${mixed} undirected edge${plural(mixed)} in a directed graph ${agree(mixed, "is", "are")} written as ${options.onMixedDirection} (onMixedDirection), and the format holds one direction per file`,
3639
+ null,
3640
+ mixed
3641
+ );
3642
+ }
3643
+ }
3644
+ if (snapshot.flags.multigraph && !caps.multiEdges) {
3645
+ const parallel = countParallelArcs(snapshot);
3646
+ note(
3647
+ LOSS.MULTI_EDGES,
3648
+ `${parallel} parallel edge${plural(parallel)}; the format has no parallel edges`,
3649
+ null,
3650
+ parallel
3651
+ );
3652
+ }
3653
+ if (snapshot.selfLoopCount > 0 && !caps.selfLoops) {
3654
+ note(
3655
+ LOSS.SELF_LOOPS,
3656
+ `${snapshot.selfLoopCount} self-loop${plural(snapshot.selfLoopCount)}; the format has no self-loops`,
3657
+ null,
3658
+ snapshot.selfLoopCount
3659
+ );
3660
+ }
3661
+ const edgeIds = snapshot.edges.byRole("id");
3662
+ if (caps.edgeIds === "required" && edgeIds === null && snapshot.edgeCount > 0) {
3663
+ note(
3664
+ LOSS.EDGE_IDS_GENERATED,
3665
+ "the format requires edge ids, and the graph has none; the edges are written with generated ids, which read back as a new edge id column",
3666
+ null,
3667
+ snapshot.edgeCount
3668
+ );
3669
+ } else if (caps.edgeIds === "none" && edgeIds !== null) {
3670
+ note(
3671
+ LOSS.EDGE_IDS_DROPPED,
3672
+ `edge id column "${edgeIds.meta.name}" cannot be written`,
3673
+ edgeIds.meta.name,
3674
+ snapshot.edgeCount
3675
+ );
3676
+ }
3677
+ const unrepresentable = countUnrepresentableIds(snapshot, caps.idCharset);
3678
+ if (unrepresentable > 0) {
3679
+ if (caps.idCharset === "dense-1-based") {
3680
+ note(
3681
+ LOSS.ID_RENUMBERED,
3682
+ options.sanitizeIds === "mangle" ? `${unrepresentable} node id${plural(unrepresentable)} ${agree(unrepresentable, "is", "are")} not their 1-based index; nodes are numbered 1..N, the original ids are written too, and an import with restoreMangledIds: true reads them back as the ids; they are also the labels of nodes without a label value` : `${unrepresentable} node id${plural(unrepresentable)} ${agree(unrepresentable, "is", "are")} not their 1-based index; nodes are numbered 1..N and ids kept as labels of the nodes without a label value (a node with one loses its id)`,
3683
+ null,
3684
+ unrepresentable
3685
+ );
3686
+ } else if (options.sanitizeIds === "mangle") {
3687
+ note(
3688
+ LOSS.ID_MANGLED,
3689
+ `${unrepresentable} node id${plural(unrepresentable)} ${charsetText(caps.idCharset, unrepresentable)}, so they are rewritten; the original ids are written too, and an import with restoreMangledIds: true reads them back`,
3690
+ null,
3691
+ unrepresentable
3692
+ );
3693
+ } else {
3694
+ note(
3695
+ LOSS.ID_CHARSET,
3696
+ `${unrepresentable} node id${plural(unrepresentable)} ${charsetText(caps.idCharset, unrepresentable)}, so the save fails unless sanitizeIds is "mangle"`,
3697
+ null,
3698
+ unrepresentable
3699
+ );
3700
+ }
3701
+ }
3702
+ if (extras.idsReadBack !== void 0) {
3703
+ let retyped = 0;
3704
+ for (let i = 0; i < snapshot.nodeCount; i++) {
3705
+ const id = snapshot.ids.idOf(i);
3706
+ if (coerceIdText(String(id), extras.idsReadBack) !== id) {
3707
+ retyped++;
3708
+ }
3709
+ }
3710
+ if (retyped > 0) {
3711
+ note(
3712
+ LOSS.ID_TEXT_TYPE,
3713
+ `${retyped} node id${plural(retyped)} ${agree(retyped, "reads", "read")} back with another type (a number as text, or text as a number)`,
3714
+ null,
3715
+ retyped
3716
+ );
3717
+ }
3718
+ }
3719
+ checkWeights(snapshot, extras, note);
3720
+ checkColumns(snapshot.nodes, "node", caps, extras, note);
3721
+ checkColumns(snapshot.edges, "edge", caps, extras, note);
3722
+ const graphColumns = snapshot.graph.names();
3723
+ if (graphColumns.length > 0) {
3724
+ if (caps.graphAttributes) {
3725
+ checkColumns(snapshot.graph, "graph", caps, extras, note);
3726
+ } else {
3727
+ note(
3728
+ LOSS.GRAPH_ATTRIBUTES,
3729
+ `${graphColumns.length} graph attribute${plural(graphColumns.length)} cannot be written`,
3730
+ null,
3731
+ graphColumns.length
3732
+ );
3733
+ }
3734
+ }
3735
+ for (const [name, table] of snapshot.extensions) {
3736
+ if (name.startsWith("temporal:")) {
3737
+ if (caps.temporal !== "dynamic-values") {
3738
+ note(
3739
+ LOSS.DYNAMIC_VALUES,
3740
+ `dynamic values of "${name}" (${table.rowCount} row${plural(table.rowCount)}) cannot be written`,
3741
+ name,
3742
+ table.rowCount
3743
+ );
3744
+ }
3745
+ } else {
3746
+ note(
3747
+ LOSS.EXTENSION_TABLE,
3748
+ `extension table "${name}" (${table.rowCount} row${plural(table.rowCount)}) cannot be written`,
3749
+ name,
3750
+ table.rowCount
3751
+ );
3752
+ }
3753
+ }
3754
+ return notes;
3755
+ }
3756
+ function charsetText(charset, n) {
3757
+ const are = agree(n, "is", "are");
3758
+ switch (charset) {
3759
+ case "nmtoken":
3760
+ return `${are} not XML name tokens (letters, digits and . - _ : only; no spaces)`;
3761
+ case "integer":
3762
+ return `${are} not integers`;
3763
+ default:
3764
+ return `cannot be written as ${charset} ids`;
3765
+ }
3766
+ }
3767
+ function writesAttributes(domain, extras) {
3768
+ if (domain === "node") {
3769
+ return extras.nodeAttributes ?? extras.attributes;
3770
+ }
3771
+ if (domain === "edge") {
3772
+ return extras.edgeAttributes ?? extras.attributes;
3773
+ }
3774
+ return extras.attributes;
3775
+ }
3776
+ function checkWeights(snapshot, extras, note) {
3777
+ if (extras.weights === false && explicitWeights(snapshot).weighted) {
3778
+ note(
3779
+ LOSS.WEIGHTS_DROPPED,
3780
+ `the edge weights are not written; ${snapshot.edgeCount} edge${plural(snapshot.edgeCount)} ${agree(snapshot.edgeCount, "reads", "read")} back with weight 1`,
3781
+ null,
3782
+ snapshot.edgeCount
3783
+ );
3784
+ }
3785
+ }
3786
+ const ROLE_WORDS = {
3787
+ label: "labels",
3788
+ weight: "weights",
3789
+ id: "ids",
3790
+ position: "positions",
3791
+ originalId: "original ids"
3792
+ };
3793
+ function checkColumns(table, domain, caps, extras, note) {
3794
+ for (const column of table) {
3795
+ const { meta } = column;
3796
+ const { name, role } = meta;
3797
+ if (role !== null && STRUCTURAL_ROLES.has(role)) {
3798
+ continue;
3799
+ }
3800
+ const label = `${domain} column "${name}"`;
3801
+ if (role !== null && extras.roleNames !== void 0) {
3802
+ const fixed = extras.roleNames[role];
3803
+ if (fixed !== void 0 && fixed !== name) {
3804
+ note(
3805
+ LOSS.COLUMN_NAME_CHANGED,
3806
+ `${label} (the ${ROLE_WORDS[role] ?? role}) is written as the format's own ${role} and reads back as "${fixed}"`,
3807
+ name,
3808
+ column.length - column.nullCount
3809
+ );
3810
+ }
3811
+ }
3812
+ if (domain === "edge" && role === "id") {
3813
+ continue;
3814
+ }
3815
+ const named = extras.writtenColumns?.[domain]?.includes(name) ?? false;
3816
+ if (writesAttributes(domain, extras) === false && !named && !(role !== null && (extras.roles?.has(role) ?? false))) {
3817
+ note(LOSS.COLUMN_DROPPED, `${label} is not written`, name, column.length - column.nullCount);
3818
+ continue;
3819
+ }
3820
+ if (role === "timeText") {
3821
+ if (extras.temporalText !== true) {
3822
+ note(
3823
+ LOSS.TEMPORAL_TEXT,
3824
+ `${label} (the original text of a date or time column) cannot be written`,
3825
+ name,
3826
+ column.length - column.nullCount
3827
+ );
3828
+ }
3829
+ continue;
3830
+ }
3831
+ if (role === "position") {
3832
+ if (!caps.positions) {
3833
+ note(LOSS.POSITIONS, `${label} (positions) cannot be written`, name, column.length - column.nullCount);
3834
+ } else if (extras.positionDtype !== void 0 && meta.dtype !== extras.positionDtype) {
3835
+ note(
3836
+ LOSS.DTYPE,
3837
+ `${label} (positions) is ${meta.dtype}; the format reads positions back as ${extras.positionDtype}`,
3838
+ name,
3839
+ column.length - column.nullCount
3840
+ );
3841
+ }
3842
+ continue;
3843
+ }
3844
+ if (role !== null && VIZ_ROLES.has(role)) {
3845
+ if (!caps.viz) {
3846
+ note(LOSS.VIZ, `${label} (${role}) cannot be written`, name, column.length - column.nullCount);
3847
+ }
3848
+ continue;
3849
+ }
3850
+ if (role !== null && HIERARCHY_ROLES.has(role)) {
3851
+ if (!caps.hierarchy) {
3852
+ note(LOSS.HIERARCHY, `${label} (${role}) cannot be written`, name, column.length - column.nullCount);
3853
+ }
3854
+ continue;
3855
+ }
3856
+ if (role !== null && TEMPORAL_ROLES.has(role)) {
3857
+ if (caps.temporal === "none") {
3858
+ note(LOSS.TEMPORAL, `${label} (${role}) cannot be written`, name, column.length - column.nullCount);
3859
+ }
3860
+ continue;
3861
+ }
3862
+ if (role === "spells") {
3863
+ if (caps.temporal !== "spells" && caps.temporal !== "dynamic-values") {
3864
+ note(LOSS.SPELLS, `${label} (spells) cannot be written`, name, column.length - column.nullCount);
3865
+ }
3866
+ continue;
3867
+ }
3868
+ if (role === "open" || role === "spellsOpen") {
3869
+ if (extras.openIntervals !== true) {
3870
+ note(
3871
+ LOSS.OPEN_INTERVAL,
3872
+ `${label} (open intervals) cannot be written`,
3873
+ name,
3874
+ column.length - column.nullCount
3875
+ );
3876
+ }
3877
+ continue;
3878
+ }
3879
+ if (role !== null && !(extras.roles?.has(role) ?? false)) {
3880
+ note(
3881
+ LOSS.ROLE,
3882
+ `${label} (${role}) is written as a plain attribute; the format has no ${role} slot and the role is lost`,
3883
+ name,
3884
+ column.length - column.nullCount
3885
+ );
3886
+ }
3887
+ if (meta.dynamic && caps.temporal !== "dynamic-values") {
3888
+ note(LOSS.DYNAMIC_VALUES, `${label} is dynamic; only its static value can be written`, name, null);
3889
+ }
3890
+ checkDtype(column, label, caps, note);
3891
+ if (meta.default !== void 0 && !caps.defaults) {
3892
+ note(LOSS.DEFAULT, `${label} declares a default; the format has no defaults`, name, null);
3893
+ }
3894
+ if (meta.options !== null && !caps.options) {
3895
+ note(LOSS.OPTIONS, `${label} declares options; the format has no enumerations`, name, null);
3896
+ }
3897
+ }
3898
+ }
3899
+ function checkDtype(column, label, caps, note) {
3900
+ const { meta } = column;
3901
+ const { name } = meta;
3902
+ const set = column.length - column.nullCount;
3903
+ switch (meta.dtype) {
3904
+ case "list":
3905
+ if (!caps.lists) {
3906
+ note(LOSS.LIST, `${label} is a list; the format has no lists`, name, set);
3907
+ } else if (meta.itemDtype !== null && !caps.dtypes.includes(meta.itemDtype)) {
3908
+ note(
3909
+ LOSS.DTYPE,
3910
+ `${label} holds ${meta.itemDtype} items; the format cannot keep that dtype`,
3911
+ name,
3912
+ set
3913
+ );
3914
+ } else if (meta.itemDtype === "dict") {
3915
+ note(LOSS.DTYPE, `${label} holds dict items; list items read back as string`, name, set);
3916
+ }
3917
+ break;
3918
+ case "json":
3919
+ if (!caps.json) {
3920
+ note(LOSS.JSON, `${label} holds nested values; the format has no nested values`, name, set);
3921
+ }
3922
+ break;
3923
+ default:
3924
+ if (!caps.dtypes.includes(meta.dtype)) {
3925
+ note(LOSS.DTYPE, `${label} is ${meta.dtype}; the format cannot keep that dtype`, name, set);
3926
+ }
3927
+ if (meta.components > 1 && !caps.components) {
3928
+ note(
3929
+ LOSS.COMPONENTS,
3930
+ `${label} has ${meta.components} components; the format has no strides`,
3931
+ name,
3932
+ set
3933
+ );
3934
+ }
3935
+ break;
3936
+ }
3937
+ }
3938
+ function countMixedEdges(snapshot) {
3939
+ if (!snapshot.directed) {
3940
+ return 0;
3941
+ }
3942
+ const directed = snapshot.edges.byRole("directed");
3943
+ if (directed === null || directed.dtype !== "bool") {
3944
+ return 0;
3945
+ }
3946
+ const pair = snapshot.edges.byRole("pair");
3947
+ let undirectedRows = 0;
3948
+ let paired = 0;
3949
+ for (let e = 0; e < snapshot.edgeCount; e++) {
3950
+ if (directed.isSet(e) && directed.value(e) === false) {
3951
+ undirectedRows++;
3952
+ if (pair !== null && pair.dtype === "u32" && pair.isSet(e) && pair.data[e] !== INVALID_INDEX) {
3953
+ paired++;
3954
+ }
3955
+ }
3956
+ }
3957
+ return paired / 2 + (undirectedRows - paired);
3958
+ }
3959
+ function countParallelArcs(snapshot) {
3960
+ const { rowPtr, colIdx, nodeCount } = snapshot;
3961
+ let count = 0;
3962
+ for (let u = 0; u < nodeCount; u++) {
3963
+ for (let a = rowPtr[u] + 1; a < rowPtr[u + 1]; a++) {
3964
+ if (colIdx[a] === colIdx[a - 1]) {
3965
+ count++;
3966
+ }
3967
+ }
3968
+ }
3969
+ return snapshot.directed ? count : Math.ceil(count / 2);
3970
+ }
3971
+ const NAME_CHAR_RANGES = [
3972
+ [45, 46],
3973
+ [48, 58],
3974
+ [65, 90],
3975
+ [95, 95],
3976
+ [97, 122],
3977
+ [183, 183],
3978
+ [192, 214],
3979
+ [216, 246],
3980
+ [248, 893],
3981
+ [895, 8191],
3982
+ [8204, 8205],
3983
+ [8255, 8256],
3984
+ [8304, 8591],
3985
+ [11264, 12271],
3986
+ [12289, 55295],
3987
+ [63744, 64975],
3988
+ [65008, 65533],
3989
+ [65536, 983039]
3990
+ ];
3991
+ function isNameChar(cp) {
3992
+ for (const [lo, hi] of NAME_CHAR_RANGES) {
3993
+ if (cp < lo) {
3994
+ return false;
3995
+ }
3996
+ if (cp <= hi) {
3997
+ return true;
3998
+ }
3999
+ }
4000
+ return false;
4001
+ }
4002
+ function isNmtoken(text) {
4003
+ if (text.length === 0) {
4004
+ return false;
4005
+ }
4006
+ for (const ch of text) {
4007
+ const cp = ch.codePointAt(0);
4008
+ if (cp === void 0 || !isNameChar(cp)) {
4009
+ return false;
4010
+ }
4011
+ }
4012
+ return true;
4013
+ }
4014
+ function isRepresentableId(id, charset) {
4015
+ switch (charset) {
4016
+ case "any":
4017
+ return true;
4018
+ case "nmtoken":
4019
+ return isNmtoken(String(id));
4020
+ case "integer":
4021
+ return typeof id === "number" && Number.isSafeInteger(id);
4022
+ case "dense-1-based":
4023
+ return false;
4024
+ default: {
4025
+ const name = charset;
4026
+ throw new GraphFormatError("E_UNSUPPORTED", `unknown id charset ${name}`, { charset: name });
4027
+ }
4028
+ }
4029
+ }
4030
+ function countUnrepresentableIds(snapshot, charset) {
4031
+ const { ids } = snapshot;
4032
+ if (charset === "any") {
4033
+ return 0;
4034
+ }
4035
+ if (charset === "dense-1-based") {
4036
+ if (ids.kind === "identity" && ids.offset === 1) {
4037
+ return 0;
4038
+ }
4039
+ let changed = 0;
4040
+ for (let i = 0; i < ids.size; i++) {
4041
+ if (ids.idOf(i) !== i + 1) {
4042
+ changed++;
4043
+ }
4044
+ }
4045
+ return changed;
4046
+ }
4047
+ let count = 0;
4048
+ for (let i = 0; i < ids.size; i++) {
4049
+ if (!isRepresentableId(ids.idOf(i), charset)) {
4050
+ count++;
4051
+ }
4052
+ }
4053
+ return count;
4054
+ }
4055
+ function sanitizeIds(snapshot, charset, mode) {
4056
+ const { ids } = snapshot;
4057
+ const n = ids.size;
4058
+ if (charset === "dense-1-based") {
4059
+ const changed = countUnrepresentableIds(snapshot, charset);
4060
+ return {
4061
+ charset,
4062
+ changed,
4063
+ idAt: (i) => i + 1,
4064
+ isChanged: (i) => ids.idOf(i) !== i + 1,
4065
+ originalAt: (i) => ids.idOf(i)
4066
+ };
4067
+ }
4068
+ const unchanged = {
4069
+ charset,
4070
+ changed: 0,
4071
+ idAt: (i) => ids.idOf(i),
4072
+ isChanged: () => false,
4073
+ originalAt: (i) => ids.idOf(i)
4074
+ };
4075
+ if (charset === "any") {
4076
+ return unchanged;
4077
+ }
4078
+ const bad = [];
4079
+ for (let i = 0; i < n; i++) {
4080
+ if (!isRepresentableId(ids.idOf(i), charset)) {
4081
+ bad.push(i);
4082
+ }
4083
+ }
4084
+ if (bad.length === 0) {
4085
+ return unchanged;
4086
+ }
4087
+ if (mode === "error") {
4088
+ const first = ids.idOf(bad[0]);
4089
+ throw new GraphFormatError(
4090
+ "E_INVALID_ID",
4091
+ `${bad.length} node id${plural(bad.length)} ${charsetText(charset, bad.length)} (first: ${JSON.stringify(first)} at index ${bad[0]}); pass sanitizeIds: "mangle" to rewrite them`,
4092
+ { reason: "charset", charset, count: bad.length, id: first, index: bad[0] }
4093
+ );
4094
+ }
4095
+ const written = /* @__PURE__ */ new Map();
4096
+ if (charset === "nmtoken") {
4097
+ const used = /* @__PURE__ */ new Set();
4098
+ for (let i = 0; i < n; i++) {
4099
+ const id = ids.idOf(i);
4100
+ if (isRepresentableId(id, charset)) {
4101
+ used.add(String(id));
4102
+ }
4103
+ }
4104
+ for (const i of bad) {
4105
+ const base = mangleNmtoken(String(ids.idOf(i)));
4106
+ let candidate = base;
4107
+ for (let k = 2; used.has(candidate); k++) {
4108
+ candidate = `${base}_${k}`;
4109
+ }
4110
+ used.add(candidate);
4111
+ written.set(i, candidate);
4112
+ }
4113
+ } else {
4114
+ const used = /* @__PURE__ */ new Set();
4115
+ for (let i = 0; i < n; i++) {
4116
+ const id = ids.idOf(i);
4117
+ if (typeof id === "number" && Number.isSafeInteger(id)) {
4118
+ used.add(id);
4119
+ }
4120
+ }
4121
+ let next = 0;
4122
+ for (const i of bad) {
4123
+ while (used.has(next)) {
4124
+ next++;
4125
+ }
4126
+ used.add(next);
4127
+ written.set(i, next);
4128
+ next++;
4129
+ }
4130
+ }
4131
+ return {
4132
+ charset,
4133
+ changed: bad.length,
4134
+ idAt: (i) => written.get(i) ?? ids.idOf(i),
4135
+ isChanged: (i) => written.has(i),
4136
+ originalAt: (i) => ids.idOf(i)
4137
+ };
4138
+ }
4139
+ function mangleNmtoken(text) {
4140
+ let out = "";
4141
+ for (const ch of text) {
4142
+ const cp = ch.codePointAt(0);
4143
+ out += cp !== void 0 && isNameChar(cp) ? ch : "_";
4144
+ }
4145
+ return out.length === 0 ? "_" : out;
4146
+ }
4147
+ export {
4148
+ agree as $,
4149
+ COLUMN_TYPE_CODE as A,
4150
+ BAD_DEFAULT_CODE as B,
4151
+ COLUMN_RENAMED_CODE as C,
4152
+ DIRECTION_FORCED_CODE as D,
4153
+ EMPTY_INPUT_CODE as E,
4154
+ ELEMENT_ISSUE as F,
4155
+ INPUT_ISSUE as G,
4156
+ HYPEREDGE_CODE as H,
4157
+ ID_MERGED_CODE as I,
4158
+ ID_TEXT_TYPE_CODE as J,
4159
+ ROLE_DROPPED_CODE as K,
4160
+ LOSS as L,
4161
+ MIXED_DIRECTION_CODE as M,
4162
+ NO_GRAPH_CODE as N,
4163
+ OPTION_IGNORED_CODE as O,
4164
+ PRECISION_CODE as P,
4165
+ PARENTS_DROPPED_CODE as Q,
4166
+ ROLE_TAKEN_CODE as R,
4167
+ SINK_OPTION_CODE as S,
4168
+ MUTUAL_AS_UNDIRECTED_CODE as T,
4169
+ UNKNOWN_ATTR_TYPE_CODE as U,
4170
+ BAD_ASPECT_BLOCK_CODE as V,
4171
+ MULTI_ASPECT_FRAGMENT_CODE as W,
4172
+ XML_SYNTAX_CODE as X,
4173
+ ASPECT_ORDER_CODE as Y,
4174
+ STATUS_FAILED_CODE as Z,
4175
+ STATUS_WARNING_CODE as _,
4176
+ checkCapabilities as a,
4177
+ COLUMN_DROPPED_CODE as a$,
4178
+ uniqueColumnName as a0,
4179
+ declareResolved as a1,
4180
+ JSON_NONSTANDARD_NUMBER_CODE as a2,
4181
+ BAD_VALUE_CODE as a3,
4182
+ textChunks as a4,
4183
+ MAX_TEXT_LENGTH as a5,
4184
+ tooLarge as a6,
4185
+ chooseGraph as a7,
4186
+ ImportReportBuilder as a8,
4187
+ idText as a9,
4188
+ NODE_ORDER_CODE as aA,
4189
+ GRAPH_COLUMN_AS_METADATA_CODE as aB,
4190
+ TYPEDEF_NODES_CODE as aC,
4191
+ RELATION_ASSUMED_CODE as aD,
4192
+ sanitizeIds as aE,
4193
+ formatDecimal as aF,
4194
+ formatInteger as aG,
4195
+ canonicalId as aH,
4196
+ coerceIdText as aI,
4197
+ survivesF32 as aJ,
4198
+ isWeightField as aK,
4199
+ parseWeightText as aL,
4200
+ isAbortError as aM,
4201
+ BAD_LINE_CODE as aN,
4202
+ messageOf as aO,
4203
+ describe as aP,
4204
+ UNKNOWN_OPTION_CODE as aQ,
4205
+ normalizeInput as aR,
4206
+ foreignKind as aS,
4207
+ ImportError as aT,
4208
+ FETCH_CODE as aU,
4209
+ EDGES_MERGED_CODE as aV,
4210
+ SELF_LOOPS_DROPPED_CODE as aW,
4211
+ WEIGHT_NOT_FOUND_CODE as aX,
4212
+ lockReader as aY,
4213
+ abortable as aZ,
4214
+ BAD_OPTIONS_CODE as a_,
4215
+ formatF32 as aa,
4216
+ formatF64 as ab,
4217
+ DictHeuristic as ac,
4218
+ TOO_LARGE_CODE as ad,
4219
+ AMBIGUOUS_GRAPH_NAME_CODE as ae,
4220
+ GRAPH_NOT_FOUND_CODE as af,
4221
+ SINGLE_OBJECT_ASPECT_CODE as ag,
4222
+ STYLES_NOT_IMPORTED_CODE as ah,
4223
+ PARENT_CYCLE_CODE as ai,
4224
+ WIDENED_CODE as aj,
4225
+ SYNTAX_CODE as ak,
4226
+ resolveImportOptions as al,
4227
+ throwIfAborted as am,
4228
+ reportUnusedOptions as an,
4229
+ reportSinkOptions as ao,
4230
+ graphChosen as ap,
4231
+ DirectionResolver as aq,
4232
+ IdCoercer as ar,
4233
+ weightFromValue as as,
4234
+ COLUMN_AS_PROPERTY_VALUE_CODE as at,
4235
+ ROLE_ASSUMED_CODE as au,
4236
+ formatNumber as av,
4237
+ isNameChar as aw,
4238
+ XML_ILLEGAL_CHAR_CODE as ax,
4239
+ RENAMED_CODE as ay,
4240
+ LineReader as az,
4241
+ plural as b,
4242
+ otherFormatDialect as b$,
4243
+ COLUMN_RENAMED_LOSS_CODE as b0,
4244
+ CONTROL_CHARACTER_CODE as b1,
4245
+ DEFAULT_ERROR_LIMIT as b2,
4246
+ DIRECTED_COLUMN as b3,
4247
+ DIRECTION_DROPPED_CODE as b4,
4248
+ DUPLICATE_EDGE_CODE as b5,
4249
+ EMPTY_COLUMN_DROPPED_CODE as b6,
4250
+ EQUATION_AS_TEXT_CODE as b7,
4251
+ FOREIGN_FORMAT_CODE as b8,
4252
+ ID_TEXT_COLLISION_CODE as b9,
4253
+ isNmtoken as bA,
4254
+ mangleNmtoken as bB,
4255
+ readText as bC,
4256
+ refusedSave as bD,
4257
+ countMixedEdges as bE,
4258
+ canonicalEncoding as bF,
4259
+ TIME_TEXT_ROLE as bG,
4260
+ TIME_TEXT_SUFFIX as bH,
4261
+ declareAttribute as bI,
4262
+ overflowsToInfinity as bJ,
4263
+ parseDeclaredTemporal as bK,
4264
+ parseDeclaredValue as bL,
4265
+ losesPrecision as bM,
4266
+ parseTimeText as bN,
4267
+ splitListText as bO,
4268
+ timeTextCompanion as bP,
4269
+ parseDecimalText as bQ,
4270
+ formatTimeValue as bR,
4271
+ mapDeclaredType as bS,
4272
+ joinListText as bT,
4273
+ formatTemporal as bU,
4274
+ DICT_SAMPLE_ROWS as bV,
4275
+ reportWeightPrecision as bW,
4276
+ takenIn as bX,
4277
+ declareOn as bY,
4278
+ parseTemporal as bZ,
4279
+ withArticle as b_,
4280
+ INTEGRAL_F64_CODE as ba,
4281
+ ISSUES_SUPPRESSED_CODE as bb,
4282
+ MUTUAL_COLUMN as bc,
4283
+ MUTUAL_EXPANDED_CODE as bd,
4284
+ NONFINITE_AS_NULL_CODE as be,
4285
+ NO_CAPABILITIES as bf,
4286
+ OPTIONS_GAINED_CODE as bg,
4287
+ PAIR_COLUMN as bh,
4288
+ PARSE_ERROR_CODE as bi,
4289
+ SELF_LOOP_CODE as bj,
4290
+ STORAGE_CLASS_CODE as bk,
4291
+ TEMPORAL_DROPPED_CODE as bl,
4292
+ TEMPORAL_TEXT_DROPPED_CODE as bm,
4293
+ TEXT_INFERRED_CODE as bn,
4294
+ UNKNOWN_TYPE_CODE as bo,
4295
+ WEIGHTS_DROPPED_CODE as bp,
4296
+ WEIGHT_KEY_CLASH_CODE as bq,
4297
+ coerceId as br,
4298
+ declareCompanion as bs,
4299
+ decodeEntryName as bt,
4300
+ edgeWeights as bu,
4301
+ forDecodedText as bv,
4302
+ formatGmlReal as bw,
4303
+ inputLength as bx,
4304
+ isCanonicalIntegerText as by,
4305
+ isImportInput as bz,
4306
+ capabilities as c,
4307
+ readBytes as c0,
4308
+ elementCount as c1,
4309
+ DIRECTION_REFUSED_CODE as d,
4310
+ explicitWeights as e,
4311
+ STRAY_TEXT_CODE as f,
4312
+ UNKNOWN_ELEMENT_CODE as g,
4313
+ UNKNOWN_XML_ATTRIBUTE_CODE as h,
4314
+ DANGLING_REFERENCE_CODE as i,
4315
+ COUNT_MISMATCH_CODE as j,
4316
+ COUNT_HINT_CODE as k,
4317
+ MULTIPLE_GRAPHS_CODE as l,
4318
+ DUPLICATE_EDGE_ID_CODE as m,
4319
+ DUPLICATE_NODE_CODE as n,
4320
+ DUPLICATE_ATTRIBUTE_CODE as o,
4321
+ pairFolding as p,
4322
+ UNKNOWN_PARENT_CODE as q,
4323
+ resolveExportOptions as r,
4324
+ MISSING_ENDPOINT_CODE as s,
4325
+ MISSING_ID_CODE as t,
4326
+ DUPLICATE_KEY_CODE as u,
4327
+ ENCODING_CONFLICT_CODE as v,
4328
+ UNKNOWN_ENCODING_CODE as w,
4329
+ ENCODING_FALLBACK_CODE as x,
4330
+ INVALID_ENCODING_CODE as y,
4331
+ INVALID_UTF8_CODE as z
4332
+ };
4333
+ //# sourceMappingURL=export-BTI4yQgy.js.map