@graphty/graph-io 0.3.47 → 0.3.49

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 (770) hide show
  1. package/dist/chunks/{approximations-wWjCRzKj.js → approximations-Bzn3L-je.js} +2 -2
  2. package/dist/chunks/{approximations-wWjCRzKj.js.map → approximations-Bzn3L-je.js.map} +1 -1
  3. package/dist/chunks/bends-BGXjv_U4.js +129 -0
  4. package/dist/chunks/bends-BGXjv_U4.js.map +1 -0
  5. package/dist/chunks/{block-DiGq58c3.js → block-iptrlMBb.js} +947 -134
  6. package/dist/chunks/block-iptrlMBb.js.map +1 -0
  7. package/dist/chunks/choose-CczZJaX_.js +717 -0
  8. package/dist/chunks/choose-CczZJaX_.js.map +1 -0
  9. package/dist/chunks/codes-BE2xir2k.js +157 -0
  10. package/dist/chunks/codes-BE2xir2k.js.map +1 -0
  11. package/dist/chunks/{constants-BKwqelYD.js → constants-CKkYLPtt.js} +2 -2
  12. package/dist/chunks/{constants-BKwqelYD.js.map → constants-CKkYLPtt.js.map} +1 -1
  13. package/dist/chunks/context-C3p0RQxR.js +664 -0
  14. package/dist/chunks/context-C3p0RQxR.js.map +1 -0
  15. package/dist/chunks/{convert-BcQ8_jMo.js → convert-Ct2zelbQ.js} +7 -2
  16. package/dist/chunks/convert-Ct2zelbQ.js.map +1 -0
  17. package/dist/chunks/credentials-DXHx7nwR.js +349 -0
  18. package/dist/chunks/credentials-DXHx7nwR.js.map +1 -0
  19. package/dist/chunks/cx-export-Bt6NoqTQ.js +259 -0
  20. package/dist/chunks/cx-export-Bt6NoqTQ.js.map +1 -0
  21. package/dist/chunks/descriptor-B28U25x4.js +60 -0
  22. package/dist/chunks/descriptor-B28U25x4.js.map +1 -0
  23. package/dist/chunks/descriptor-C-YDhtsn.js +48 -0
  24. package/dist/chunks/descriptor-C-YDhtsn.js.map +1 -0
  25. package/dist/chunks/descriptor-DLA5kINx.js +142 -0
  26. package/dist/chunks/descriptor-DLA5kINx.js.map +1 -0
  27. package/dist/chunks/{emit-CwU8cUmG.js → emit-BwHQkZle.js} +1690 -103
  28. package/dist/chunks/emit-BwHQkZle.js.map +1 -0
  29. package/dist/chunks/{escape-CgzxiYPg.js → escape-CuCIzNMB.js} +12 -12
  30. package/dist/chunks/{escape-CgzxiYPg.js.map → escape-CuCIzNMB.js.map} +1 -1
  31. package/dist/chunks/{export-BvqAXCKh.js → export-Cha4dRFz.js} +48 -1780
  32. package/dist/chunks/export-Cha4dRFz.js.map +1 -0
  33. package/dist/chunks/{exporter--Mk9gXCJ.js → exporter-BP6otMO6.js} +6 -4
  34. package/dist/chunks/{exporter--Mk9gXCJ.js.map → exporter-BP6otMO6.js.map} +1 -1
  35. package/dist/chunks/{exporter-CrDWIyiq.js → exporter-D2CETOMK.js} +1222 -154
  36. package/dist/chunks/exporter-D2CETOMK.js.map +1 -0
  37. package/dist/chunks/{exporter-DndFlGSa.js → exporter-D9yMtocA.js} +7 -6
  38. package/dist/chunks/{exporter-DndFlGSa.js.map → exporter-D9yMtocA.js.map} +1 -1
  39. package/dist/chunks/exporter-_jrBTnos.js +1009 -0
  40. package/dist/chunks/exporter-_jrBTnos.js.map +1 -0
  41. package/dist/chunks/{exporter-CJgfhF-l.js → exporter-nDfxIK5D.js} +9 -7
  42. package/dist/chunks/{exporter-CJgfhF-l.js.map → exporter-nDfxIK5D.js.map} +1 -1
  43. package/dist/chunks/format-BXiAb-1h.js +408 -0
  44. package/dist/chunks/format-BXiAb-1h.js.map +1 -0
  45. package/dist/chunks/{generic-Dq1ntt9q.js → generic-ymWCETAJ.js} +387 -31
  46. package/dist/chunks/generic-ymWCETAJ.js.map +1 -0
  47. package/dist/chunks/{importer-CMmeMWlC.js → importer-B92x1xY5.js} +15 -263
  48. package/dist/chunks/importer-B92x1xY5.js.map +1 -0
  49. package/dist/chunks/{importer-DiZRmOQG.js → importer-CT9mJ1nn.js} +328 -90
  50. package/dist/chunks/importer-CT9mJ1nn.js.map +1 -0
  51. package/dist/chunks/{importer-COTK9Tsl.js → importer-DaLTjbds.js} +116 -1099
  52. package/dist/chunks/importer-DaLTjbds.js.map +1 -0
  53. package/dist/chunks/{importer-iFYPEKaJ.js → importer-GREKMdIf.js} +28 -16
  54. package/dist/chunks/importer-GREKMdIf.js.map +1 -0
  55. package/dist/chunks/{importer-BSvfrX_h.js → importer-PqaaKKnY.js} +23 -1016
  56. package/dist/chunks/importer-PqaaKKnY.js.map +1 -0
  57. package/dist/chunks/{importer-yh_aBCU6.js → importer-Vn5QvmmJ.js} +66 -12
  58. package/dist/chunks/importer-Vn5QvmmJ.js.map +1 -0
  59. package/dist/chunks/{importer-e6LGpqHB.js → importer-vRq4h3j5.js} +1470 -354
  60. package/dist/chunks/importer-vRq4h3j5.js.map +1 -0
  61. package/dist/chunks/input-CAxt_aV-.js +1397 -0
  62. package/dist/chunks/input-CAxt_aV-.js.map +1 -0
  63. package/dist/chunks/{json-elements-DJZRZ6jd.js → json-elements-Cq76WjnZ.js} +4 -4
  64. package/dist/chunks/{json-elements-DJZRZ6jd.js.map → json-elements-Cq76WjnZ.js.map} +1 -1
  65. package/dist/chunks/{lexicon-CT69Kd87.js → lexicon-Clf4QIyl.js} +299 -77
  66. package/dist/chunks/lexicon-Clf4QIyl.js.map +1 -0
  67. package/dist/chunks/{ontology-export-G4MqRdux.js → ontology-export-OMo91mb0.js} +4 -3
  68. package/dist/chunks/{ontology-export-G4MqRdux.js.map → ontology-export-OMo91mb0.js.map} +1 -1
  69. package/dist/chunks/{records-CiaWZrFH.js → records-NJiYvekn.js} +2 -2
  70. package/dist/chunks/{records-CiaWZrFH.js.map → records-NJiYvekn.js.map} +1 -1
  71. package/dist/chunks/{format-BpQBx8MZ.js → report-CwMfYa9J.js} +70 -127
  72. package/dist/chunks/report-CwMfYa9J.js.map +1 -0
  73. package/dist/chunks/round-trip-Zm3_ivgq.js +79 -0
  74. package/dist/chunks/round-trip-Zm3_ivgq.js.map +1 -0
  75. package/dist/chunks/sigv4-EokFic1V.js +247 -0
  76. package/dist/chunks/sigv4-EokFic1V.js.map +1 -0
  77. package/dist/chunks/{styles-BQnsga7p.js → styles-CCs214_3.js} +1300 -168
  78. package/dist/chunks/styles-CCs214_3.js.map +1 -0
  79. package/dist/chunks/styles-Cm62yyQX.js +2812 -0
  80. package/dist/chunks/styles-Cm62yyQX.js.map +1 -0
  81. package/dist/chunks/styles-DPQQIig4.js +1928 -0
  82. package/dist/chunks/styles-DPQQIig4.js.map +1 -0
  83. package/dist/chunks/styles-yed-UMFdNqze.js +1213 -0
  84. package/dist/chunks/styles-yed-UMFdNqze.js.map +1 -0
  85. package/dist/chunks/{text-CzJNFOS9.js → text-ystE2bYi.js} +2 -2
  86. package/dist/chunks/{text-CzJNFOS9.js.map → text-ystE2bYi.js.map} +1 -1
  87. package/dist/csv.js +7 -5
  88. package/dist/csv.js.map +1 -1
  89. package/dist/cx.js +5 -4
  90. package/dist/cx.js.map +1 -1
  91. package/dist/cx2.js +2 -2
  92. package/dist/cys.js +1 -1
  93. package/dist/dot.js +5 -4
  94. package/dist/dot.js.map +1 -1
  95. package/dist/gexf.js +42 -10
  96. package/dist/gexf.js.map +1 -1
  97. package/dist/gml.js +850 -193
  98. package/dist/gml.js.map +1 -1
  99. package/dist/graph-io.js +1189 -220
  100. package/dist/graph-io.js.map +1 -1
  101. package/dist/graphml.js +3 -3
  102. package/dist/json.js +3 -2
  103. package/dist/neo4j.js +6 -4
  104. package/dist/neo4j.js.map +1 -1
  105. package/dist/obo.js +1 -1
  106. package/dist/pajek.js +1 -1
  107. package/dist/positions.js +45 -3
  108. package/dist/positions.js.map +1 -1
  109. package/dist/sources-cypher.d.ts +1 -0
  110. package/dist/sources-cypher.js +1351 -0
  111. package/dist/sources-cypher.js.map +1 -0
  112. package/dist/sources-ndex.d.ts +1 -0
  113. package/dist/sources-ndex.js +278 -0
  114. package/dist/sources-ndex.js.map +1 -0
  115. package/dist/sources-rest.d.ts +1 -0
  116. package/dist/sources-rest.js +1377 -0
  117. package/dist/sources-rest.js.map +1 -0
  118. package/dist/sources-sparql.d.ts +1 -0
  119. package/dist/sources-sparql.js +405 -0
  120. package/dist/sources-sparql.js.map +1 -0
  121. package/dist/src/common/report.d.ts +6 -3
  122. package/dist/src/common/report.d.ts.map +1 -1
  123. package/dist/src/common/report.js +15 -9
  124. package/dist/src/common/report.js.map +1 -1
  125. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  126. package/dist/src/formats/cx/importer.js +5 -1
  127. package/dist/src/formats/cx/importer.js.map +1 -1
  128. package/dist/src/formats/cx/styles.d.ts +24 -1
  129. package/dist/src/formats/cx/styles.d.ts.map +1 -1
  130. package/dist/src/formats/cx/styles.js +118 -11
  131. package/dist/src/formats/cx/styles.js.map +1 -1
  132. package/dist/src/formats/cx2/importer.d.ts.map +1 -1
  133. package/dist/src/formats/cx2/importer.js +1 -0
  134. package/dist/src/formats/cx2/importer.js.map +1 -1
  135. package/dist/src/formats/cx2/styles.d.ts.map +1 -1
  136. package/dist/src/formats/cx2/styles.js +3 -1
  137. package/dist/src/formats/cx2/styles.js.map +1 -1
  138. package/dist/src/formats/cys/importer.d.ts.map +1 -1
  139. package/dist/src/formats/cys/importer.js +1 -0
  140. package/dist/src/formats/cys/importer.js.map +1 -1
  141. package/dist/src/formats/cys/styles.d.ts +2 -0
  142. package/dist/src/formats/cys/styles.d.ts.map +1 -1
  143. package/dist/src/formats/cys/styles.js +15 -7
  144. package/dist/src/formats/cys/styles.js.map +1 -1
  145. package/dist/src/formats/dot/drawing.d.ts +98 -0
  146. package/dist/src/formats/dot/drawing.d.ts.map +1 -0
  147. package/dist/src/formats/dot/drawing.js +734 -0
  148. package/dist/src/formats/dot/drawing.js.map +1 -0
  149. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  150. package/dist/src/formats/dot/importer.js +108 -31
  151. package/dist/src/formats/dot/importer.js.map +1 -1
  152. package/dist/src/formats/dot/label-places.d.ts +34 -0
  153. package/dist/src/formats/dot/label-places.d.ts.map +1 -0
  154. package/dist/src/formats/dot/label-places.js +179 -0
  155. package/dist/src/formats/dot/label-places.js.map +1 -0
  156. package/dist/src/formats/dot/record.d.ts +50 -0
  157. package/dist/src/formats/dot/record.d.ts.map +1 -0
  158. package/dist/src/formats/dot/record.js +275 -0
  159. package/dist/src/formats/dot/record.js.map +1 -0
  160. package/dist/src/formats/dot/styles.d.ts +62 -2
  161. package/dist/src/formats/dot/styles.d.ts.map +1 -1
  162. package/dist/src/formats/dot/styles.js +1457 -120
  163. package/dist/src/formats/dot/styles.js.map +1 -1
  164. package/dist/src/formats/gexf/dialog-metrics.d.ts +15 -0
  165. package/dist/src/formats/gexf/dialog-metrics.d.ts.map +1 -0
  166. package/dist/src/formats/gexf/dialog-metrics.js +59 -0
  167. package/dist/src/formats/gexf/dialog-metrics.js.map +1 -0
  168. package/dist/src/formats/gexf/importer.d.ts +7 -0
  169. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  170. package/dist/src/formats/gexf/importer.js +41 -5
  171. package/dist/src/formats/gexf/importer.js.map +1 -1
  172. package/dist/src/formats/gexf/preview.d.ts +77 -0
  173. package/dist/src/formats/gexf/preview.d.ts.map +1 -0
  174. package/dist/src/formats/gexf/preview.js +191 -0
  175. package/dist/src/formats/gexf/preview.js.map +1 -0
  176. package/dist/src/formats/gexf/schema.d.ts.map +1 -1
  177. package/dist/src/formats/gexf/schema.js +2 -1
  178. package/dist/src/formats/gexf/schema.js.map +1 -1
  179. package/dist/src/formats/gexf/styles.d.ts +60 -16
  180. package/dist/src/formats/gexf/styles.d.ts.map +1 -1
  181. package/dist/src/formats/gexf/styles.js +883 -131
  182. package/dist/src/formats/gexf/styles.js.map +1 -1
  183. package/dist/src/formats/gml/importer.d.ts +5 -2
  184. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  185. package/dist/src/formats/gml/importer.js +258 -71
  186. package/dist/src/formats/gml/importer.js.map +1 -1
  187. package/dist/src/formats/gml/index.d.ts +1 -1
  188. package/dist/src/formats/gml/index.d.ts.map +1 -1
  189. package/dist/src/formats/gml/index.js +1 -1
  190. package/dist/src/formats/gml/index.js.map +1 -1
  191. package/dist/src/formats/gml/positions.d.ts +7 -0
  192. package/dist/src/formats/gml/positions.d.ts.map +1 -1
  193. package/dist/src/formats/gml/positions.js +29 -7
  194. package/dist/src/formats/gml/positions.js.map +1 -1
  195. package/dist/src/formats/gml/styles.d.ts.map +1 -1
  196. package/dist/src/formats/gml/styles.js +756 -103
  197. package/dist/src/formats/gml/styles.js.map +1 -1
  198. package/dist/src/formats/graphml/styles-plain.d.ts.map +1 -1
  199. package/dist/src/formats/graphml/styles-plain.js +8 -12
  200. package/dist/src/formats/graphml/styles-plain.js.map +1 -1
  201. package/dist/src/formats/graphml/styles-yed.d.ts +21 -15
  202. package/dist/src/formats/graphml/styles-yed.d.ts.map +1 -1
  203. package/dist/src/formats/graphml/styles-yed.js +749 -148
  204. package/dist/src/formats/graphml/styles-yed.js.map +1 -1
  205. package/dist/src/formats/graphml/styles-yfiles3.d.ts +1 -1
  206. package/dist/src/formats/graphml/styles-yfiles3.d.ts.map +1 -1
  207. package/dist/src/formats/graphml/styles-yfiles3.js +429 -64
  208. package/dist/src/formats/graphml/styles-yfiles3.js.map +1 -1
  209. package/dist/src/formats/graphml/yfiles.d.ts +3 -3
  210. package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
  211. package/dist/src/formats/graphml/yfiles.js +16 -6
  212. package/dist/src/formats/graphml/yfiles.js.map +1 -1
  213. package/dist/src/formats/json/dialect.d.ts +3 -2
  214. package/dist/src/formats/json/dialect.d.ts.map +1 -1
  215. package/dist/src/formats/json/dialect.js +39 -5
  216. package/dist/src/formats/json/dialect.js.map +1 -1
  217. package/dist/src/formats/json/importer.d.ts +13 -2
  218. package/dist/src/formats/json/importer.d.ts.map +1 -1
  219. package/dist/src/formats/json/importer.js +42 -6
  220. package/dist/src/formats/json/importer.js.map +1 -1
  221. package/dist/src/formats/json/index.d.ts +1 -1
  222. package/dist/src/formats/json/index.d.ts.map +1 -1
  223. package/dist/src/formats/json/index.js +1 -1
  224. package/dist/src/formats/json/index.js.map +1 -1
  225. package/dist/src/formats/json/positions.d.ts +5 -2
  226. package/dist/src/formats/json/positions.d.ts.map +1 -1
  227. package/dist/src/formats/json/positions.js +20 -4
  228. package/dist/src/formats/json/positions.js.map +1 -1
  229. package/dist/src/formats/json/styles.d.ts +12 -1
  230. package/dist/src/formats/json/styles.d.ts.map +1 -1
  231. package/dist/src/formats/json/styles.js +1755 -136
  232. package/dist/src/formats/json/styles.js.map +1 -1
  233. package/dist/src/formats/pajek/draw.d.ts +96 -0
  234. package/dist/src/formats/pajek/draw.d.ts.map +1 -0
  235. package/dist/src/formats/pajek/draw.js +372 -0
  236. package/dist/src/formats/pajek/draw.js.map +1 -0
  237. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  238. package/dist/src/formats/pajek/exporter.js +70 -51
  239. package/dist/src/formats/pajek/exporter.js.map +1 -1
  240. package/dist/src/formats/pajek/importer.d.ts +9 -0
  241. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  242. package/dist/src/formats/pajek/importer.js +233 -102
  243. package/dist/src/formats/pajek/importer.js.map +1 -1
  244. package/dist/src/formats/pajek/index.d.ts +1 -0
  245. package/dist/src/formats/pajek/index.d.ts.map +1 -1
  246. package/dist/src/formats/pajek/index.js.map +1 -1
  247. package/dist/src/formats/pajek/styles.d.ts +15 -7
  248. package/dist/src/formats/pajek/styles.d.ts.map +1 -1
  249. package/dist/src/formats/pajek/styles.js +1279 -114
  250. package/dist/src/formats/pajek/styles.js.map +1 -1
  251. package/dist/src/formats/pajek/syntax.d.ts +10 -1
  252. package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
  253. package/dist/src/formats/pajek/syntax.js +26 -2
  254. package/dist/src/formats/pajek/syntax.js.map +1 -1
  255. package/dist/src/formats/xgmml/emit.d.ts +1 -0
  256. package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
  257. package/dist/src/formats/xgmml/emit.js +65 -5
  258. package/dist/src/formats/xgmml/emit.js.map +1 -1
  259. package/dist/src/formats/xgmml/styles.d.ts +23 -3
  260. package/dist/src/formats/xgmml/styles.d.ts.map +1 -1
  261. package/dist/src/formats/xgmml/styles.js +278 -60
  262. package/dist/src/formats/xgmml/styles.js.map +1 -1
  263. package/dist/src/index.d.ts +10 -2
  264. package/dist/src/index.d.ts.map +1 -1
  265. package/dist/src/index.js +11 -2
  266. package/dist/src/index.js.map +1 -1
  267. package/dist/src/positions/convert.d.ts.map +1 -1
  268. package/dist/src/positions/convert.js +11 -1
  269. package/dist/src/positions/convert.js.map +1 -1
  270. package/dist/src/positions/extract.d.ts.map +1 -1
  271. package/dist/src/positions/extract.js +53 -1
  272. package/dist/src/positions/extract.js.map +1 -1
  273. package/dist/src/positions/index.d.ts +1 -1
  274. package/dist/src/positions/index.d.ts.map +1 -1
  275. package/dist/src/positions/types.d.ts +59 -0
  276. package/dist/src/positions/types.d.ts.map +1 -1
  277. package/dist/src/registry.d.ts +173 -1
  278. package/dist/src/registry.d.ts.map +1 -1
  279. package/dist/src/registry.js +196 -1
  280. package/dist/src/registry.js.map +1 -1
  281. package/dist/src/sources/builtins.d.ts +11 -0
  282. package/dist/src/sources/builtins.d.ts.map +1 -0
  283. package/dist/src/sources/builtins.js +53 -0
  284. package/dist/src/sources/builtins.js.map +1 -0
  285. package/dist/src/sources/codes.d.ts +230 -0
  286. package/dist/src/sources/codes.d.ts.map +1 -0
  287. package/dist/src/sources/codes.js +58 -0
  288. package/dist/src/sources/codes.js.map +1 -0
  289. package/dist/src/sources/context.d.ts +112 -0
  290. package/dist/src/sources/context.d.ts.map +1 -0
  291. package/dist/src/sources/context.js +740 -0
  292. package/dist/src/sources/context.js.map +1 -0
  293. package/dist/src/sources/credentials.d.ts +179 -0
  294. package/dist/src/sources/credentials.d.ts.map +1 -0
  295. package/dist/src/sources/credentials.js +301 -0
  296. package/dist/src/sources/credentials.js.map +1 -0
  297. package/dist/src/sources/cypher/descriptor.d.ts +21 -0
  298. package/dist/src/sources/cypher/descriptor.d.ts.map +1 -0
  299. package/dist/src/sources/cypher/descriptor.js +124 -0
  300. package/dist/src/sources/cypher/descriptor.js.map +1 -0
  301. package/dist/src/sources/cypher/flatten.d.ts +72 -0
  302. package/dist/src/sources/cypher/flatten.d.ts.map +1 -0
  303. package/dist/src/sources/cypher/flatten.js +279 -0
  304. package/dist/src/sources/cypher/flatten.js.map +1 -0
  305. package/dist/src/sources/cypher/index.d.ts +33 -0
  306. package/dist/src/sources/cypher/index.d.ts.map +1 -0
  307. package/dist/src/sources/cypher/index.js +511 -0
  308. package/dist/src/sources/cypher/index.js.map +1 -0
  309. package/dist/src/sources/cypher/params.d.ts +40 -0
  310. package/dist/src/sources/cypher/params.d.ts.map +1 -0
  311. package/dist/src/sources/cypher/params.js +6 -0
  312. package/dist/src/sources/cypher/params.js.map +1 -0
  313. package/dist/src/sources/cypher/profiles.d.ts +44 -0
  314. package/dist/src/sources/cypher/profiles.d.ts.map +1 -0
  315. package/dist/src/sources/cypher/profiles.js +61 -0
  316. package/dist/src/sources/cypher/profiles.js.map +1 -0
  317. package/dist/src/sources/cypher/query-builder.d.ts +123 -0
  318. package/dist/src/sources/cypher/query-builder.d.ts.map +1 -0
  319. package/dist/src/sources/cypher/query-builder.js +267 -0
  320. package/dist/src/sources/cypher/query-builder.js.map +1 -0
  321. package/dist/src/sources/cypher/transports/bolt.d.ts +21 -0
  322. package/dist/src/sources/cypher/transports/bolt.d.ts.map +1 -0
  323. package/dist/src/sources/cypher/transports/bolt.js +185 -0
  324. package/dist/src/sources/cypher/transports/bolt.js.map +1 -0
  325. package/dist/src/sources/cypher/transports/neptune-analytics.d.ts +15 -0
  326. package/dist/src/sources/cypher/transports/neptune-analytics.d.ts.map +1 -0
  327. package/dist/src/sources/cypher/transports/neptune-analytics.js +38 -0
  328. package/dist/src/sources/cypher/transports/neptune-analytics.js.map +1 -0
  329. package/dist/src/sources/cypher/transports/neptune-https.d.ts +31 -0
  330. package/dist/src/sources/cypher/transports/neptune-https.d.ts.map +1 -0
  331. package/dist/src/sources/cypher/transports/neptune-https.js +104 -0
  332. package/dist/src/sources/cypher/transports/neptune-https.js.map +1 -0
  333. package/dist/src/sources/cypher/transports/query-api.d.ts +14 -0
  334. package/dist/src/sources/cypher/transports/query-api.d.ts.map +1 -0
  335. package/dist/src/sources/cypher/transports/query-api.js +80 -0
  336. package/dist/src/sources/cypher/transports/query-api.js.map +1 -0
  337. package/dist/src/sources/cypher/transports/transport.d.ts +78 -0
  338. package/dist/src/sources/cypher/transports/transport.d.ts.map +1 -0
  339. package/dist/src/sources/cypher/transports/transport.js +77 -0
  340. package/dist/src/sources/cypher/transports/transport.js.map +1 -0
  341. package/dist/src/sources/cypher/types-map.d.ts +91 -0
  342. package/dist/src/sources/cypher/types-map.d.ts.map +1 -0
  343. package/dist/src/sources/cypher/types-map.js +306 -0
  344. package/dist/src/sources/cypher/types-map.js.map +1 -0
  345. package/dist/src/sources/define.d.ts +47 -0
  346. package/dist/src/sources/define.d.ts.map +1 -0
  347. package/dist/src/sources/define.js +173 -0
  348. package/dist/src/sources/define.js.map +1 -0
  349. package/dist/src/sources/fail.d.ts +33 -0
  350. package/dist/src/sources/fail.d.ts.map +1 -0
  351. package/dist/src/sources/fail.js +49 -0
  352. package/dist/src/sources/fail.js.map +1 -0
  353. package/dist/src/sources/ids.d.ts +69 -0
  354. package/dist/src/sources/ids.d.ts.map +1 -0
  355. package/dist/src/sources/ids.js +69 -0
  356. package/dist/src/sources/ids.js.map +1 -0
  357. package/dist/src/sources/ndex/client.d.ts +31 -0
  358. package/dist/src/sources/ndex/client.d.ts.map +1 -0
  359. package/dist/src/sources/ndex/client.js +90 -0
  360. package/dist/src/sources/ndex/client.js.map +1 -0
  361. package/dist/src/sources/ndex/descriptor.d.ts +10 -0
  362. package/dist/src/sources/ndex/descriptor.d.ts.map +1 -0
  363. package/dist/src/sources/ndex/descriptor.js +55 -0
  364. package/dist/src/sources/ndex/descriptor.js.map +1 -0
  365. package/dist/src/sources/ndex/expand.d.ts +20 -0
  366. package/dist/src/sources/ndex/expand.d.ts.map +1 -0
  367. package/dist/src/sources/ndex/expand.js +87 -0
  368. package/dist/src/sources/ndex/expand.js.map +1 -0
  369. package/dist/src/sources/ndex/index.d.ts +25 -0
  370. package/dist/src/sources/ndex/index.d.ts.map +1 -0
  371. package/dist/src/sources/ndex/index.js +191 -0
  372. package/dist/src/sources/ndex/index.js.map +1 -0
  373. package/dist/src/sources/ndex/params.d.ts +17 -0
  374. package/dist/src/sources/ndex/params.d.ts.map +1 -0
  375. package/dist/src/sources/ndex/params.js +6 -0
  376. package/dist/src/sources/ndex/params.js.map +1 -0
  377. package/dist/src/sources/ndex/share-url.d.ts +40 -0
  378. package/dist/src/sources/ndex/share-url.d.ts.map +1 -0
  379. package/dist/src/sources/ndex/share-url.js +64 -0
  380. package/dist/src/sources/ndex/share-url.js.map +1 -0
  381. package/dist/src/sources/params.d.ts +31 -0
  382. package/dist/src/sources/params.d.ts.map +1 -0
  383. package/dist/src/sources/params.js +6 -0
  384. package/dist/src/sources/params.js.map +1 -0
  385. package/dist/src/sources/registry.d.ts +118 -0
  386. package/dist/src/sources/registry.d.ts.map +1 -0
  387. package/dist/src/sources/registry.js +193 -0
  388. package/dist/src/sources/registry.js.map +1 -0
  389. package/dist/src/sources/rest/descriptor.d.ts +16 -0
  390. package/dist/src/sources/rest/descriptor.d.ts.map +1 -0
  391. package/dist/src/sources/rest/descriptor.js +76 -0
  392. package/dist/src/sources/rest/descriptor.js.map +1 -0
  393. package/dist/src/sources/rest/index.d.ts +14 -0
  394. package/dist/src/sources/rest/index.d.ts.map +1 -0
  395. package/dist/src/sources/rest/index.js +13 -0
  396. package/dist/src/sources/rest/index.js.map +1 -0
  397. package/dist/src/sources/rest/mapping.d.ts +30 -0
  398. package/dist/src/sources/rest/mapping.d.ts.map +1 -0
  399. package/dist/src/sources/rest/mapping.js +362 -0
  400. package/dist/src/sources/rest/mapping.js.map +1 -0
  401. package/dist/src/sources/rest/openalex.d.ts +27 -0
  402. package/dist/src/sources/rest/openalex.d.ts.map +1 -0
  403. package/dist/src/sources/rest/openalex.js +269 -0
  404. package/dist/src/sources/rest/openalex.js.map +1 -0
  405. package/dist/src/sources/rest/paging.d.ts +53 -0
  406. package/dist/src/sources/rest/paging.d.ts.map +1 -0
  407. package/dist/src/sources/rest/paging.js +138 -0
  408. package/dist/src/sources/rest/paging.js.map +1 -0
  409. package/dist/src/sources/rest/params.d.ts +216 -0
  410. package/dist/src/sources/rest/params.d.ts.map +1 -0
  411. package/dist/src/sources/rest/params.js +7 -0
  412. package/dist/src/sources/rest/params.js.map +1 -0
  413. package/dist/src/sources/rest/records.d.ts +41 -0
  414. package/dist/src/sources/rest/records.d.ts.map +1 -0
  415. package/dist/src/sources/rest/records.js +240 -0
  416. package/dist/src/sources/rest/records.js.map +1 -0
  417. package/dist/src/sources/rest/samples/deps-dev.d.ts +10 -0
  418. package/dist/src/sources/rest/samples/deps-dev.d.ts.map +1 -0
  419. package/dist/src/sources/rest/samples/deps-dev.js +47 -0
  420. package/dist/src/sources/rest/samples/deps-dev.js.map +1 -0
  421. package/dist/src/sources/rest/samples/string.d.ts +9 -0
  422. package/dist/src/sources/rest/samples/string.d.ts.map +1 -0
  423. package/dist/src/sources/rest/samples/string.js +42 -0
  424. package/dist/src/sources/rest/samples/string.js.map +1 -0
  425. package/dist/src/sources/rest/selectors.d.ts +41 -0
  426. package/dist/src/sources/rest/selectors.d.ts.map +1 -0
  427. package/dist/src/sources/rest/selectors.js +81 -0
  428. package/dist/src/sources/rest/selectors.js.map +1 -0
  429. package/dist/src/sources/rest/source.d.ts +67 -0
  430. package/dist/src/sources/rest/source.d.ts.map +1 -0
  431. package/dist/src/sources/rest/source.js +650 -0
  432. package/dist/src/sources/rest/source.js.map +1 -0
  433. package/dist/src/sources/rest/templates.d.ts +38 -0
  434. package/dist/src/sources/rest/templates.d.ts.map +1 -0
  435. package/dist/src/sources/rest/templates.js +125 -0
  436. package/dist/src/sources/rest/templates.js.map +1 -0
  437. package/dist/src/sources/run.d.ts +93 -0
  438. package/dist/src/sources/run.d.ts.map +1 -0
  439. package/dist/src/sources/run.js +673 -0
  440. package/dist/src/sources/run.js.map +1 -0
  441. package/dist/src/sources/sha256.d.ts +12 -0
  442. package/dist/src/sources/sha256.d.ts.map +1 -0
  443. package/dist/src/sources/sha256.js +95 -0
  444. package/dist/src/sources/sha256.js.map +1 -0
  445. package/dist/src/sources/sigv4.d.ts +26 -0
  446. package/dist/src/sources/sigv4.d.ts.map +1 -0
  447. package/dist/src/sources/sigv4.js +184 -0
  448. package/dist/src/sources/sigv4.js.map +1 -0
  449. package/dist/src/sources/sparql/descriptor.d.ts +10 -0
  450. package/dist/src/sources/sparql/descriptor.d.ts.map +1 -0
  451. package/dist/src/sources/sparql/descriptor.js +64 -0
  452. package/dist/src/sources/sparql/descriptor.js.map +1 -0
  453. package/dist/src/sources/sparql/index.d.ts +28 -0
  454. package/dist/src/sources/sparql/index.d.ts.map +1 -0
  455. package/dist/src/sources/sparql/index.js +314 -0
  456. package/dist/src/sources/sparql/index.js.map +1 -0
  457. package/dist/src/sources/sparql/ntriples.d.ts +69 -0
  458. package/dist/src/sources/sparql/ntriples.d.ts.map +1 -0
  459. package/dist/src/sources/sparql/ntriples.js +180 -0
  460. package/dist/src/sources/sparql/ntriples.js.map +1 -0
  461. package/dist/src/sources/sparql/params.d.ts +27 -0
  462. package/dist/src/sources/sparql/params.d.ts.map +1 -0
  463. package/dist/src/sources/sparql/params.js +5 -0
  464. package/dist/src/sources/sparql/params.js.map +1 -0
  465. package/dist/src/sources/sparql/query.d.ts +72 -0
  466. package/dist/src/sources/sparql/query.d.ts.map +1 -0
  467. package/dist/src/sources/sparql/query.js +113 -0
  468. package/dist/src/sources/sparql/query.js.map +1 -0
  469. package/dist/src/sources/testing.d.ts +96 -0
  470. package/dist/src/sources/testing.d.ts.map +1 -0
  471. package/dist/src/sources/testing.js +138 -0
  472. package/dist/src/sources/testing.js.map +1 -0
  473. package/dist/src/sources/types.d.ts +696 -0
  474. package/dist/src/sources/types.d.ts.map +1 -0
  475. package/dist/src/sources/types.js +10 -0
  476. package/dist/src/sources/types.js.map +1 -0
  477. package/dist/src/styles/annotations.d.ts +61 -5
  478. package/dist/src/styles/annotations.d.ts.map +1 -1
  479. package/dist/src/styles/annotations.js +130 -22
  480. package/dist/src/styles/annotations.js.map +1 -1
  481. package/dist/src/styles/canon/bends.d.ts +46 -0
  482. package/dist/src/styles/canon/bends.d.ts.map +1 -1
  483. package/dist/src/styles/canon/bends.js +123 -0
  484. package/dist/src/styles/canon/bends.js.map +1 -1
  485. package/dist/src/styles/canon/color-tables.d.ts +6 -1
  486. package/dist/src/styles/canon/color-tables.d.ts.map +1 -1
  487. package/dist/src/styles/canon/color-tables.js +10 -4
  488. package/dist/src/styles/canon/color-tables.js.map +1 -1
  489. package/dist/src/styles/canon/color.d.ts +3 -1
  490. package/dist/src/styles/canon/color.d.ts.map +1 -1
  491. package/dist/src/styles/canon/color.js +103 -3
  492. package/dist/src/styles/canon/color.js.map +1 -1
  493. package/dist/src/styles/canon/enums.d.ts +2 -2
  494. package/dist/src/styles/canon/enums.d.ts.map +1 -1
  495. package/dist/src/styles/canon/enums.js +82 -7
  496. package/dist/src/styles/canon/enums.js.map +1 -1
  497. package/dist/src/styles/canon/graphviz.d.ts +12 -3
  498. package/dist/src/styles/canon/graphviz.d.ts.map +1 -1
  499. package/dist/src/styles/canon/graphviz.js +57 -9
  500. package/dist/src/styles/canon/graphviz.js.map +1 -1
  501. package/dist/src/styles/canon/number.d.ts +8 -0
  502. package/dist/src/styles/canon/number.d.ts.map +1 -1
  503. package/dist/src/styles/canon/number.js +18 -0
  504. package/dist/src/styles/canon/number.js.map +1 -1
  505. package/dist/src/styles/canon/text.d.ts +29 -2
  506. package/dist/src/styles/canon/text.d.ts.map +1 -1
  507. package/dist/src/styles/canon/text.js +156 -16
  508. package/dist/src/styles/canon/text.js.map +1 -1
  509. package/dist/src/styles/codes.d.ts +2 -0
  510. package/dist/src/styles/codes.d.ts.map +1 -1
  511. package/dist/src/styles/codes.js +2 -0
  512. package/dist/src/styles/codes.js.map +1 -1
  513. package/dist/src/styles/cyjs/cascade.d.ts.map +1 -1
  514. package/dist/src/styles/cyjs/cascade.js +1037 -35
  515. package/dist/src/styles/cyjs/cascade.js.map +1 -1
  516. package/dist/src/styles/cyjs/defaults-table.d.ts.map +1 -1
  517. package/dist/src/styles/cyjs/defaults-table.js +5 -0
  518. package/dist/src/styles/cyjs/defaults-table.js.map +1 -1
  519. package/dist/src/styles/cyjs/emit.d.ts.map +1 -1
  520. package/dist/src/styles/cyjs/emit.js +216 -12
  521. package/dist/src/styles/cyjs/emit.js.map +1 -1
  522. package/dist/src/styles/cyjs/face.d.ts +20 -0
  523. package/dist/src/styles/cyjs/face.d.ts.map +1 -0
  524. package/dist/src/styles/cyjs/face.js +332 -0
  525. package/dist/src/styles/cyjs/face.js.map +1 -0
  526. package/dist/src/styles/cyjs/mappers.d.ts +48 -2
  527. package/dist/src/styles/cyjs/mappers.d.ts.map +1 -1
  528. package/dist/src/styles/cyjs/mappers.js +463 -26
  529. package/dist/src/styles/cyjs/mappers.js.map +1 -1
  530. package/dist/src/styles/cyjs/routes.d.ts +53 -0
  531. package/dist/src/styles/cyjs/routes.d.ts.map +1 -0
  532. package/dist/src/styles/cyjs/routes.js +360 -0
  533. package/dist/src/styles/cyjs/routes.js.map +1 -0
  534. package/dist/src/styles/cytoscape/charts.d.ts +23 -0
  535. package/dist/src/styles/cytoscape/charts.d.ts.map +1 -0
  536. package/dist/src/styles/cytoscape/charts.js +560 -0
  537. package/dist/src/styles/cytoscape/charts.js.map +1 -0
  538. package/dist/src/styles/cytoscape/emit.d.ts.map +1 -1
  539. package/dist/src/styles/cytoscape/emit.js +204 -44
  540. package/dist/src/styles/cytoscape/emit.js.map +1 -1
  541. package/dist/src/styles/cytoscape/lexicon.d.ts +97 -3
  542. package/dist/src/styles/cytoscape/lexicon.d.ts.map +1 -1
  543. package/dist/src/styles/cytoscape/lexicon.js +413 -79
  544. package/dist/src/styles/cytoscape/lexicon.js.map +1 -1
  545. package/dist/src/styles/cytoscape/mappings.d.ts +30 -0
  546. package/dist/src/styles/cytoscape/mappings.d.ts.map +1 -1
  547. package/dist/src/styles/cytoscape/mappings.js +92 -0
  548. package/dist/src/styles/cytoscape/mappings.js.map +1 -1
  549. package/dist/src/styles/cytoscape/resolve.d.ts +46 -3
  550. package/dist/src/styles/cytoscape/resolve.d.ts.map +1 -1
  551. package/dist/src/styles/cytoscape/resolve.js +632 -22
  552. package/dist/src/styles/cytoscape/resolve.js.map +1 -1
  553. package/dist/src/styles/cytoscape/translate.d.ts.map +1 -1
  554. package/dist/src/styles/cytoscape/translate.js +10 -10
  555. package/dist/src/styles/cytoscape/translate.js.map +1 -1
  556. package/dist/src/styles/defaults.d.ts +50 -0
  557. package/dist/src/styles/defaults.d.ts.map +1 -1
  558. package/dist/src/styles/defaults.js +315 -37
  559. package/dist/src/styles/defaults.js.map +1 -1
  560. package/dist/src/styles/index.d.ts +4 -3
  561. package/dist/src/styles/index.d.ts.map +1 -1
  562. package/dist/src/styles/index.js +3 -2
  563. package/dist/src/styles/index.js.map +1 -1
  564. package/dist/src/styles/internal.d.ts +1 -0
  565. package/dist/src/styles/internal.d.ts.map +1 -1
  566. package/dist/src/styles/internal.js +1 -0
  567. package/dist/src/styles/internal.js.map +1 -1
  568. package/dist/src/styles/io/block.d.ts.map +1 -1
  569. package/dist/src/styles/io/block.js +9 -0
  570. package/dist/src/styles/io/block.js.map +1 -1
  571. package/dist/src/styles/io/generic.d.ts.map +1 -1
  572. package/dist/src/styles/io/generic.js +56 -16
  573. package/dist/src/styles/io/generic.js.map +1 -1
  574. package/dist/src/styles/io/round-trip.d.ts +56 -0
  575. package/dist/src/styles/io/round-trip.d.ts.map +1 -0
  576. package/dist/src/styles/io/round-trip.js +138 -0
  577. package/dist/src/styles/io/round-trip.js.map +1 -0
  578. package/dist/src/styles/io/writer.d.ts.map +1 -1
  579. package/dist/src/styles/io/writer.js +13 -4
  580. package/dist/src/styles/io/writer.js.map +1 -1
  581. package/dist/src/styles/notes.d.ts.map +1 -1
  582. package/dist/src/styles/notes.js +1 -0
  583. package/dist/src/styles/notes.js.map +1 -1
  584. package/dist/src/styles/plan/features.d.ts +1 -1
  585. package/dist/src/styles/plan/features.d.ts.map +1 -1
  586. package/dist/src/styles/plan/features.js +22 -2
  587. package/dist/src/styles/plan/features.js.map +1 -1
  588. package/dist/src/styles/plan/index.d.ts +1 -1
  589. package/dist/src/styles/plan/index.d.ts.map +1 -1
  590. package/dist/src/styles/plan/index.js +1 -1
  591. package/dist/src/styles/plan/index.js.map +1 -1
  592. package/dist/src/styles/plan/plan.d.ts.map +1 -1
  593. package/dist/src/styles/plan/plan.js +61 -4
  594. package/dist/src/styles/plan/plan.js.map +1 -1
  595. package/dist/src/styles/plan/resolve.d.ts +13 -1
  596. package/dist/src/styles/plan/resolve.d.ts.map +1 -1
  597. package/dist/src/styles/plan/resolve.js +53 -6
  598. package/dist/src/styles/plan/resolve.js.map +1 -1
  599. package/dist/src/styles/slots.d.ts +14 -0
  600. package/dist/src/styles/slots.d.ts.map +1 -0
  601. package/dist/src/styles/slots.js +20 -0
  602. package/dist/src/styles/slots.js.map +1 -0
  603. package/dist/src/styles/types.d.ts +638 -5
  604. package/dist/src/styles/types.d.ts.map +1 -1
  605. package/dist/src/styles/vocabulary.d.ts +3 -2
  606. package/dist/src/styles/vocabulary.d.ts.map +1 -1
  607. package/dist/src/styles/vocabulary.js +218 -1
  608. package/dist/src/styles/vocabulary.js.map +1 -1
  609. package/dist/src/types.d.ts +19 -5
  610. package/dist/src/types.d.ts.map +1 -1
  611. package/dist/src/types.js.map +1 -1
  612. package/dist/styles.js +29 -238
  613. package/dist/styles.js.map +1 -1
  614. package/dist/xgmml.js +3 -3
  615. package/docs/samples/people.json +6 -0
  616. package/package.json +53 -8
  617. package/src/common/report.ts +27 -7
  618. package/src/formats/cx/importer.ts +6 -1
  619. package/src/formats/cx/styles.ts +144 -9
  620. package/src/formats/cx2/importer.ts +1 -0
  621. package/src/formats/cx2/styles.ts +3 -1
  622. package/src/formats/cys/importer.ts +1 -0
  623. package/src/formats/cys/styles.ts +27 -5
  624. package/src/formats/dot/drawing.ts +799 -0
  625. package/src/formats/dot/importer.ts +120 -35
  626. package/src/formats/dot/label-places.ts +228 -0
  627. package/src/formats/dot/record.ts +336 -0
  628. package/src/formats/dot/styles.ts +1657 -154
  629. package/src/formats/gexf/dialog-metrics.ts +61 -0
  630. package/src/formats/gexf/importer.ts +50 -5
  631. package/src/formats/gexf/preview.ts +217 -0
  632. package/src/formats/gexf/schema.ts +2 -1
  633. package/src/formats/gexf/styles.ts +1144 -142
  634. package/src/formats/gml/importer.ts +291 -76
  635. package/src/formats/gml/index.ts +1 -1
  636. package/src/formats/gml/positions.ts +29 -7
  637. package/src/formats/gml/styles.ts +854 -111
  638. package/src/formats/graphml/styles-plain.ts +8 -23
  639. package/src/formats/graphml/styles-yed.ts +821 -159
  640. package/src/formats/graphml/styles-yfiles3.ts +485 -63
  641. package/src/formats/graphml/yfiles.ts +19 -6
  642. package/src/formats/json/dialect.ts +41 -5
  643. package/src/formats/json/importer.ts +59 -7
  644. package/src/formats/json/index.ts +1 -0
  645. package/src/formats/json/positions.ts +22 -5
  646. package/src/formats/json/styles.ts +2041 -185
  647. package/src/formats/pajek/draw.ts +458 -0
  648. package/src/formats/pajek/exporter.ts +81 -49
  649. package/src/formats/pajek/importer.ts +278 -103
  650. package/src/formats/pajek/index.ts +1 -0
  651. package/src/formats/pajek/styles.ts +1382 -133
  652. package/src/formats/pajek/syntax.ts +27 -2
  653. package/src/formats/xgmml/emit.ts +73 -5
  654. package/src/formats/xgmml/styles.ts +331 -71
  655. package/src/index.ts +94 -0
  656. package/src/positions/convert.ts +12 -1
  657. package/src/positions/extract.ts +55 -1
  658. package/src/positions/index.ts +1 -0
  659. package/src/positions/types.ts +60 -0
  660. package/src/registry.ts +326 -1
  661. package/src/sources/builtins.ts +63 -0
  662. package/src/sources/codes.ts +235 -0
  663. package/src/sources/context.ts +894 -0
  664. package/src/sources/credentials.ts +409 -0
  665. package/src/sources/cypher/descriptor.ts +131 -0
  666. package/src/sources/cypher/flatten.ts +323 -0
  667. package/src/sources/cypher/index.ts +628 -0
  668. package/src/sources/cypher/params.ts +41 -0
  669. package/src/sources/cypher/profiles.ts +78 -0
  670. package/src/sources/cypher/query-builder.ts +327 -0
  671. package/src/sources/cypher/transports/bolt.ts +228 -0
  672. package/src/sources/cypher/transports/neptune-analytics.ts +41 -0
  673. package/src/sources/cypher/transports/neptune-https.ts +122 -0
  674. package/src/sources/cypher/transports/query-api.ts +100 -0
  675. package/src/sources/cypher/transports/transport.ts +139 -0
  676. package/src/sources/cypher/types-map.ts +418 -0
  677. package/src/sources/define.ts +195 -0
  678. package/src/sources/fail.ts +70 -0
  679. package/src/sources/ids.ts +80 -0
  680. package/src/sources/ndex/client.ts +102 -0
  681. package/src/sources/ndex/descriptor.ts +64 -0
  682. package/src/sources/ndex/expand.ts +100 -0
  683. package/src/sources/ndex/index.ts +235 -0
  684. package/src/sources/ndex/params.ts +17 -0
  685. package/src/sources/ndex/share-url.ts +84 -0
  686. package/src/sources/params.ts +32 -0
  687. package/src/sources/registry.ts +325 -0
  688. package/src/sources/rest/descriptor.ts +79 -0
  689. package/src/sources/rest/index.ts +22 -0
  690. package/src/sources/rest/mapping.ts +401 -0
  691. package/src/sources/rest/openalex.ts +288 -0
  692. package/src/sources/rest/paging.ts +180 -0
  693. package/src/sources/rest/params.ts +243 -0
  694. package/src/sources/rest/records.ts +289 -0
  695. package/src/sources/rest/samples/deps-dev.ts +49 -0
  696. package/src/sources/rest/samples/string.ts +44 -0
  697. package/src/sources/rest/selectors.ts +91 -0
  698. package/src/sources/rest/source.ts +776 -0
  699. package/src/sources/rest/templates.ts +151 -0
  700. package/src/sources/run.ts +793 -0
  701. package/src/sources/sha256.ts +99 -0
  702. package/src/sources/sigv4.ts +209 -0
  703. package/src/sources/sparql/descriptor.ts +67 -0
  704. package/src/sources/sparql/index.ts +356 -0
  705. package/src/sources/sparql/ntriples.ts +219 -0
  706. package/src/sources/sparql/params.ts +28 -0
  707. package/src/sources/sparql/query.ts +162 -0
  708. package/src/sources/testing.ts +210 -0
  709. package/src/sources/types.ts +776 -0
  710. package/src/styles/annotations.ts +201 -27
  711. package/src/styles/canon/bends.ts +137 -0
  712. package/src/styles/canon/color-tables.ts +10 -4
  713. package/src/styles/canon/color.ts +105 -3
  714. package/src/styles/canon/enums.ts +99 -8
  715. package/src/styles/canon/graphviz.ts +71 -10
  716. package/src/styles/canon/number.ts +19 -0
  717. package/src/styles/canon/text.ts +187 -16
  718. package/src/styles/codes.ts +2 -0
  719. package/src/styles/cyjs/cascade.ts +1193 -38
  720. package/src/styles/cyjs/defaults-table.ts +5 -0
  721. package/src/styles/cyjs/emit.ts +247 -16
  722. package/src/styles/cyjs/face.ts +372 -0
  723. package/src/styles/cyjs/mappers.ts +498 -28
  724. package/src/styles/cyjs/routes.ts +432 -0
  725. package/src/styles/cytoscape/charts.ts +684 -0
  726. package/src/styles/cytoscape/emit.ts +220 -44
  727. package/src/styles/cytoscape/lexicon.ts +459 -80
  728. package/src/styles/cytoscape/mappings.ts +108 -0
  729. package/src/styles/cytoscape/resolve.ts +763 -23
  730. package/src/styles/cytoscape/translate.ts +11 -11
  731. package/src/styles/defaults.ts +436 -38
  732. package/src/styles/index.ts +5 -0
  733. package/src/styles/internal.ts +1 -0
  734. package/src/styles/io/block.ts +10 -0
  735. package/src/styles/io/generic.ts +79 -23
  736. package/src/styles/io/round-trip.ts +202 -0
  737. package/src/styles/io/writer.ts +14 -4
  738. package/src/styles/notes.ts +1 -0
  739. package/src/styles/plan/features.ts +23 -2
  740. package/src/styles/plan/index.ts +1 -1
  741. package/src/styles/plan/plan.ts +69 -5
  742. package/src/styles/plan/resolve.ts +61 -6
  743. package/src/styles/slots.ts +25 -0
  744. package/src/styles/types.ts +658 -4
  745. package/src/styles/vocabulary.ts +226 -3
  746. package/src/types.ts +19 -5
  747. package/dist/chunks/block-DiGq58c3.js.map +0 -1
  748. package/dist/chunks/choose--jM0yYCo.js +0 -57
  749. package/dist/chunks/choose--jM0yYCo.js.map +0 -1
  750. package/dist/chunks/convert-BcQ8_jMo.js.map +0 -1
  751. package/dist/chunks/emit-CwU8cUmG.js.map +0 -1
  752. package/dist/chunks/export-BvqAXCKh.js.map +0 -1
  753. package/dist/chunks/exporter-CrDWIyiq.js.map +0 -1
  754. package/dist/chunks/format-BpQBx8MZ.js.map +0 -1
  755. package/dist/chunks/generic-Dq1ntt9q.js.map +0 -1
  756. package/dist/chunks/importer-BSvfrX_h.js.map +0 -1
  757. package/dist/chunks/importer-CMmeMWlC.js.map +0 -1
  758. package/dist/chunks/importer-COTK9Tsl.js.map +0 -1
  759. package/dist/chunks/importer-DiZRmOQG.js.map +0 -1
  760. package/dist/chunks/importer-e6LGpqHB.js.map +0 -1
  761. package/dist/chunks/importer-iFYPEKaJ.js.map +0 -1
  762. package/dist/chunks/importer-yh_aBCU6.js.map +0 -1
  763. package/dist/chunks/lexicon-CT69Kd87.js.map +0 -1
  764. package/dist/chunks/styles-BQnsga7p.js.map +0 -1
  765. package/dist/chunks/styles-D3fRphrO.js +0 -690
  766. package/dist/chunks/styles-D3fRphrO.js.map +0 -1
  767. package/dist/chunks/styles-yed-BF5x3_Y5.js +0 -842
  768. package/dist/chunks/styles-yed-BF5x3_Y5.js.map +0 -1
  769. package/dist/chunks/writer-DMKvthQE.js +0 -448
  770. package/dist/chunks/writer-DMKvthQE.js.map +0 -1
@@ -5,7 +5,10 @@
5
5
  * of elements plus the size of the style, and spends from the extraction's one budget.
6
6
  */
7
7
 
8
- import type { CanonSite } from "../canon/site.js";
8
+ import type { GraphSnapshot } from "@graphty/graph-format";
9
+
10
+ import { num6 } from "../canon/number.js";
11
+ import { type CanonSite, noteAt } from "../canon/site.js";
9
12
  import { STYLE_ISSUE } from "../codes.js";
10
13
  import { toolDefaults } from "../defaults.js";
11
14
  import { StyleNotes } from "../notes.js";
@@ -21,13 +24,24 @@ import type {
21
24
  StyleWorkBudget,
22
25
  } from "../types.js";
23
26
  import { isStyleValue } from "../vocabulary.js";
27
+ import { readCytoscapeCharts } from "./charts.js";
24
28
  import {
29
+ arrowGap,
30
+ arrowProportion,
31
+ arrowSizeParser,
25
32
  colorParser,
26
33
  CYTOSCAPE_LEXICON,
34
+ cytoscapeLabelBase,
35
+ cytoscapeLabelMove,
36
+ type CytoscapeLabelPlace,
37
+ cytoscapeLabelPlace,
27
38
  type CytoscapeValueParser,
39
+ halfBack,
28
40
  isUncarriedVp,
29
41
  NODE_SIZE_VP,
42
+ opacityParser,
30
43
  sizeParser,
44
+ vpStep,
31
45
  } from "./lexicon.js";
32
46
  import {
33
47
  type CytoscapeContinuousPoint,
@@ -59,6 +73,27 @@ export interface CytoscapeElements {
59
73
  value(column: string, i: number): unknown;
60
74
  /** Each element's bypasses, by element index. */
61
75
  readonly bypasses?: readonly CytoscapeBypass[];
76
+ /**
77
+ * Edges only: each edge's source and target node index, in the order Cytoscape created the edges. With them,
78
+ * the edges Cytoscape desktop fans apart (parallel edges without bends) are marked curved; with `nodeSize` too
79
+ * (each node's larger drawn side, by node index, as `fanNodeSizes()` reads it), they are given the `fanSpacing`
80
+ * desktop spaces them by. With `nodeBox` (each node's width, height and border width, by node index), each
81
+ * self-loop without bends is given the two handles desktop draws it round.
82
+ */
83
+ readonly ends?: {
84
+ readonly source: ArrayLike<number>;
85
+ readonly target: ArrayLike<number>;
86
+ readonly nodeSize?: ArrayLike<number | null>;
87
+ readonly nodeBox?: ArrayLike<readonly [width: number, height: number, border: number] | null>;
88
+ /** Each node's center on screen, x right and y down, by node index: what an edge's label is placed by. */
89
+ readonly nodeAt?: ArrayLike<readonly [x: number, y: number] | null>;
90
+ /**
91
+ * The order Cytoscape desktop creates the file's nodes and edges in, when it is not the file's (its CX reader
92
+ * creates them in hash order): each element's rank, lower first, by index. With it, `nodeAt` and `nodeSize`,
93
+ * each fanned edge is given desktop's own anchor as its bend, so it bows to the side desktop draws it on.
94
+ */
95
+ readonly created?: { readonly node: ArrayLike<number>; readonly edge: ArrayLike<number> };
96
+ };
62
97
  }
63
98
 
64
99
  /**
@@ -76,11 +111,101 @@ export interface CytoscapeResolveOptions {
76
111
  * element the style says nothing about is null. Defaults to null.
77
112
  */
78
113
  readonly defaults?: StyleTool | null;
114
+ /** `resolveCytoscapeBypasses()` only: the edges' ends, as `CytoscapeElements.ends`. */
115
+ readonly ends?: CytoscapeElements["ends"];
116
+ /**
117
+ * `resolveCytoscapeBypasses()` only: an element's value of an attribute column, as `CytoscapeElements.value`,
118
+ * for what is drawn from the element's data (a chart's values); without it no element has any.
119
+ */
120
+ readonly value?: CytoscapeElements["value"];
121
+ }
122
+
123
+ /** How closely desktop stacks the edges it fans, 0..1: its anchors are twice this times the node size apart. */
124
+ const EDGE_STACKING_DENSITY_VP = "EDGE_STACKING_DENSITY";
125
+ /** How desktop draws parallel edges: AUTO_BEND (the default) fans them, HAYSTACK draws them straight. */
126
+ const EDGE_STACKING_VP = "EDGE_STACKING";
127
+ /** Whether an edge's label is turned along its line. */
128
+ const AUTOROTATE_VP = "EDGE_LABEL_AUTOROTATE";
129
+
130
+ /**
131
+ * A map without one key.
132
+ * @param m - the map
133
+ * @param key - the key left out
134
+ * @returns a copy without it
135
+ */
136
+ function withoutKey(m: ReadonlyMap<string, unknown>, key: string): ReadonlyMap<string, unknown> {
137
+ return new Map([...m].filter(([k]) => k !== key));
138
+ }
139
+ /** Desktop's `EDGE_STACKING_DENSITY` default. */
140
+ const EDGE_STACKING_DENSITY_DEFAULT = 0.5;
141
+
142
+ /**
143
+ * A graph's edge ends for `CytoscapeElements.ends`, with each node's larger side from the nodes' resolved `width`
144
+ * and `height`: what desktop spaces the edges it fans between two nodes by.
145
+ * @param snapshot - the graph
146
+ * @param nodes - the nodes' values per property
147
+ * @returns the ends
148
+ */
149
+ export function edgeEnds(
150
+ snapshot: GraphSnapshot,
151
+ nodes: Partial<Record<string, StyleColumn>>,
152
+ ): NonNullable<CytoscapeElements["ends"]> {
153
+ const nodeSize = Array.from({ length: snapshot.nodeCount }, (_, i) => {
154
+ const sides = [nodes.width?.[i], nodes.height?.[i]].filter((v): v is number => typeof v === "number");
155
+ return sides.length === 0 ? null : Math.max(...sides);
156
+ });
157
+ const nodeBox = Array.from({ length: snapshot.nodeCount }, (_, i) => {
158
+ const [w, h, b] = [nodes.width?.[i], nodes.height?.[i], nodes.borderWidth?.[i]];
159
+ return typeof w === "number" && typeof h === "number" ? ([w, h, typeof b === "number" ? b : 0] as const) : null;
160
+ });
161
+ const position = snapshot.nodes.byRole("position");
162
+ // stored y up unless the column says otherwise; the label places are worked out y down, as Cytoscape draws
163
+ const down = (position?.meta.extra as { yAxis?: string } | undefined)?.yAxis === "down";
164
+ const nodeAt = Array.from({ length: snapshot.nodeCount }, (_, i) => {
165
+ const v = position?.isSet(i) === true ? (position.value(i) as ArrayLike<number>) : null;
166
+ return v === null ? null : ([v[0], down ? v[1] : -v[1]] as const);
167
+ });
168
+ const { src, dst } = snapshot.edgeList();
169
+ return { source: src, target: dst, nodeSize, nodeBox, nodeAt };
79
170
  }
80
171
 
81
172
  /** Locked node sizes with no `NODE_SIZE` anywhere draw at Cytoscape's lexicon default. */
82
173
  const NODE_SIZE_FALLBACK = 50;
83
174
 
175
+ /**
176
+ * The visual property whose bypass each one takes when an element does not bypass it itself: Cytoscape desktop locks
177
+ * a bypassed parent's children too, so a session's `NODE_PAINT` bypass paints the fill and the border, a `NODE_SIZE`
178
+ * bypass sizes the node whatever `nodeSizeLocked` says, and an `EDGE_PAINT` or `EDGE_UNSELECTED_PAINT` bypass paints
179
+ * the line and its arrows (Cytoscape 3.10.5's SVG of the session specimen sheets `node-fills-borders`,
180
+ * `node-sizes-opacity` and `edges-lines`).
181
+ */
182
+ const LOCK_PARENT: ReadonlyMap<string, string> = new Map([
183
+ ["NODE_FILL_COLOR", "NODE_PAINT"],
184
+ ["NODE_BORDER_PAINT", "NODE_PAINT"],
185
+ ["NODE_WIDTH", "NODE_SIZE"],
186
+ ["NODE_HEIGHT", "NODE_SIZE"],
187
+ ["EDGE_UNSELECTED_PAINT", "EDGE_PAINT"],
188
+ ["EDGE_STROKE_UNSELECTED_PAINT", "EDGE_UNSELECTED_PAINT"],
189
+ ["EDGE_SOURCE_ARROW_UNSELECTED_PAINT", "EDGE_UNSELECTED_PAINT"],
190
+ ["EDGE_TARGET_ARROW_UNSELECTED_PAINT", "EDGE_UNSELECTED_PAINT"],
191
+ ]);
192
+
193
+ /**
194
+ * An element's bypass of a visual property: its own, else the nearest bypassed parent's (`LOCK_PARENT`).
195
+ * @param b - the element's bypasses
196
+ * @param vp - the visual property
197
+ * @returns the bypass value, or undefined
198
+ */
199
+ function lockedValue(b: NonNullable<CytoscapeBypass>, vp: string): unknown {
200
+ for (let p: string | undefined = vp; p !== undefined; p = LOCK_PARENT.get(p)) {
201
+ const v = b.get(p);
202
+ if (v !== undefined && v !== null) {
203
+ return v;
204
+ }
205
+ }
206
+ return undefined;
207
+ }
208
+
84
209
  /** A visual property and the parser that reads it for one neutral property. */
85
210
  type VpChoice = readonly [vp: string, parse: CytoscapeValueParser];
86
211
 
@@ -107,6 +232,12 @@ export function vpUsage(
107
232
  bypassed.add(to);
108
233
  }
109
234
  }
235
+ // a bypassed parent bypasses its children (LOCK_PARENT lists a parent's own entry before its children's)
236
+ for (const [child, parent] of LOCK_PARENT) {
237
+ if (bypassed.has(parent)) {
238
+ bypassed.add(child);
239
+ }
240
+ }
110
241
  const used = new Set([...style.defaults.keys(), ...style.mappings.keys(), ...bypassed]);
111
242
  return { used, bypassed };
112
243
  }
@@ -136,7 +267,8 @@ export function chooseVps(
136
267
  chosen.delete("height");
137
268
  }
138
269
  if (target === "edge" && style.dependencies.get("arrowColorMatchesEdge") === true) {
139
- if (used.has("EDGE_UNSELECTED_PAINT")) {
270
+ // the line is EDGE_UNSELECTED_PAINT's, not the stroke's, even where the style sets only the stroke
271
+ if (used.has("EDGE_UNSELECTED_PAINT") || used.has("EDGE_STROKE_UNSELECTED_PAINT")) {
140
272
  chosen.set("color", ["EDGE_UNSELECTED_PAINT", colorParser]);
141
273
  }
142
274
  chosen.delete("sourceArrowColor");
@@ -152,7 +284,13 @@ export function chooseVps(
152
284
  export type ParsedMapping =
153
285
  | { readonly kind: "passthrough"; readonly column: string }
154
286
  | { readonly kind: "discrete"; readonly column: string; readonly table: readonly (readonly [Scalar, StyleValue])[] }
155
- | { readonly kind: "continuous"; readonly column: string; readonly points: readonly ContinuousPoint[] };
287
+ | {
288
+ readonly kind: "continuous";
289
+ readonly column: string;
290
+ readonly points: readonly ContinuousPoint[];
291
+ /** The step Cytoscape rounds a value to, for an integer visual property. */
292
+ readonly step?: number;
293
+ };
156
294
 
157
295
  /**
158
296
  * Reads a mapping's raw values with a property's parser: table entries and points whose values do not parse are
@@ -160,9 +298,15 @@ export type ParsedMapping =
160
298
  * @param m - the mapping
161
299
  * @param parse - the property's parser
162
300
  * @param site - where problems are noted
301
+ * @param vp - the visual property it sets, whose type decides whether an interpolated value is rounded
163
302
  * @returns the mapping with canonical values
164
303
  */
165
- export function parseMapping(m: CytoscapeMapping, parse: CytoscapeValueParser, site: CanonSite): ParsedMapping {
304
+ export function parseMapping(
305
+ m: CytoscapeMapping,
306
+ parse: CytoscapeValueParser,
307
+ site: CanonSite,
308
+ vp: string,
309
+ ): ParsedMapping {
166
310
  switch (m.kind) {
167
311
  case "passthrough":
168
312
  return { kind: "passthrough", column: m.column };
@@ -176,8 +320,11 @@ export function parseMapping(m: CytoscapeMapping, parse: CytoscapeValueParser, s
176
320
  }
177
321
  return { kind: "discrete", column: m.column, table };
178
322
  }
179
- default:
180
- return { kind: "continuous", column: m.column, points: parsePoints(m.points, parse, site) };
323
+ default: {
324
+ const step = vpStep(vp);
325
+ const points = parsePoints(m.points, parse, site);
326
+ return { kind: "continuous", column: m.column, points, ...(step === undefined ? {} : { step }) };
327
+ }
181
328
  }
182
329
  }
183
330
 
@@ -240,7 +387,7 @@ function evalMapping(
240
387
  return j < 0 ? null : m.table[j][1];
241
388
  }
242
389
  default:
243
- return evalContinuous(m.points, numberOf(value));
390
+ return evalContinuous(m.points, numberOf(value), m.step);
244
391
  }
245
392
  }
246
393
 
@@ -283,7 +430,7 @@ function resolver(
283
430
  return b.get(from);
284
431
  }
285
432
  }
286
- return undefined;
433
+ return lockedValue(b, vp);
287
434
  };
288
435
  // a mapping parsed once per visual property and neutral property
289
436
  const mappingOf = (vp: string, parse: CytoscapeValueParser, property: string): ParsedMapping | undefined => {
@@ -296,7 +443,7 @@ function resolver(
296
443
  if (m === undefined) {
297
444
  const entries = raw.kind === "discrete" ? raw.table.length : 0;
298
445
  budget?.spend(target, 1 + entries + (raw.kind === "continuous" ? raw.points.length : 0));
299
- m = parseMapping(raw, parse, ruleSite(property));
446
+ m = parseMapping(raw, parse, ruleSite(property), vp);
300
447
  parsed.set(key, m);
301
448
  }
302
449
  return m;
@@ -321,7 +468,7 @@ function resolver(
321
468
  /**
322
469
  * Every element's value per neutral property under a Cytoscape style, the way Cytoscape draws it: per visual
323
470
  * property a bypass, else the mapping's value, else the default; `nodeSizeLocked` and `arrowColorMatchesEdge`
324
- * applied. `EDGE_CURVED` only rounds an edge's bends, so an edge without bends is `curved: false`. Visual properties
471
+ * applied (under `nodeSizeLocked` a node's own `NODE_WIDTH` or `NODE_HEIGHT` bypass still sets that dimension). `EDGE_CURVED` only rounds an edge's bends, so an edge without bends is `curved: false` unless desktop fans it out of a bundle of parallel edges (given `elements.ends`). Visual properties
325
472
  * no neutral property carries are noted as `W_STYLE_NOT_CARRIED`.
326
473
  * @param target - nodes or edges
327
474
  * @param style - the style
@@ -341,7 +488,7 @@ export function resolveCytoscape(
341
488
  const n = elements.count;
342
489
  const { used, bypassed } = vpUsage(s, elements.bypasses ?? []);
343
490
  const chosen = chooseVps(target, s, used);
344
- const { one } = resolver(target, s, elements, notes, options.budget);
491
+ const { one, bypass } = resolver(target, s, elements, notes, options.budget);
345
492
  const out: Partial<Record<string, StyleColumn>> = {};
346
493
  const column = (vp: string, parse: CytoscapeValueParser, property: string): (StyleValue | null)[] => {
347
494
  options.budget?.spend(target, n);
@@ -355,31 +502,581 @@ export function resolveCytoscape(
355
502
  out[prop] = column(vp, parse, prop);
356
503
  }
357
504
  if (target === "node" && s.dependencies.get("nodeSizeLocked") === true) {
505
+ // a node's own width or height still wins over the locked size: Cytoscape draws it
358
506
  const size = column(NODE_SIZE_VP, sizeParser, "width").map((v) => v ?? NODE_SIZE_FALLBACK);
359
- out.width = size;
360
- out.height = size.slice();
507
+ const own = (vp: string, property: string): StyleColumn =>
508
+ size.map((v, i) => {
509
+ const b = bypass(i, vp);
510
+ const parsed =
511
+ b === undefined || b === null ? null : sizeParser(b, { notes, target, property, element: i });
512
+ return parsed ?? v;
513
+ });
514
+ out.width = own("NODE_WIDTH", "width");
515
+ out.height = own("NODE_HEIGHT", "height");
516
+ }
517
+ labelDress(target, out, one, n, elements.ends);
518
+ if (target === "node") {
519
+ squashHexagons(out);
520
+ // the value as written: a chart is text, or an object in CX2; a size a number or its text
521
+ const raw: CytoscapeValueParser = (v) => {
522
+ if (typeof v === "string" || typeof v === "number") {
523
+ return String(v);
524
+ }
525
+ return typeof v === "object" && v !== null ? JSON.stringify(v) : null;
526
+ };
527
+ readCytoscapeCharts(
528
+ out,
529
+ n,
530
+ (slot, i) => {
531
+ const v = one(slot, raw, "pieColors", i);
532
+ return typeof v === "string" && v.startsWith("{") ? (JSON.parse(v) as unknown) : v;
533
+ },
534
+ (column, i) => elements.value(column, i),
535
+ s.dependencies.get("nodeCustomGraphicsSizeSync") !== false,
536
+ );
537
+ }
538
+ if (
539
+ target === "edge" &&
540
+ s.dependencies.get("arrowColorMatchesEdge") === true &&
541
+ !used.has("EDGE_UNSELECTED_PAINT") &&
542
+ used.has("EDGE_STROKE_UNSELECTED_PAINT")
543
+ ) {
544
+ // the dependency draws the line and the arrows in EDGE_UNSELECTED_PAINT, Cytoscape's own when the style has
545
+ // none: the stroke's default and its mapping are not drawn, only an element's own bypass of the stroke (below;
546
+ // Cytoscape 3.10.5 on specimen-mappings-bypass draws a passthrough of the stroke #404040, as its XGMML says)
547
+ const paint = (toolDefaults("cytoscape-fallbacks")?.edge.color?.value ?? null) as StyleValue | null;
548
+ out.color = Array.from({ length: n }, (_, i) => one("EDGE_UNSELECTED_PAINT", colorParser, "color", i) ?? paint);
361
549
  }
362
550
  if (target === "edge" && s.dependencies.get("arrowColorMatchesEdge") === true && out.color !== undefined) {
363
- out.sourceArrowColor = out.color.slice();
364
- out.targetArrowColor = out.color.slice();
551
+ // CX2's EDGE_LINE_COLOR bypass is the stroke's alone (its writer spells a desktop EDGE_UNSELECTED_PAINT
552
+ // bypass out as the line and both arrow colors): the arrows keep the style's line color (Cytoscape 3.10.5's
553
+ // SVG of the CX2 specimen-mappings-bypass, bypass-over-edge-passthrough, draws its arrow #505050)
554
+ const lineVp = chosen.get("color")?.[0];
555
+ const unbypassed = resolver(target, s, { ...elements, bypasses: [] }, notes, options.budget).one;
556
+ const arrows =
557
+ lineVp === "EDGE_LINE_COLOR"
558
+ ? Array.from({ length: n }, (_, i) => unbypassed(lineVp, colorParser, "color", i))
559
+ : out.color;
560
+ out.sourceArrowColor = arrows.slice();
561
+ out.targetArrowColor = arrows.slice();
562
+ // the dependency sets the line and the arrows from EDGE_UNSELECTED_PAINT; an element's own bypass of one of
563
+ // them still wins for that one (Cytoscape draws a bypassed EDGE_STROKE_UNSELECTED_PAINT line in its color)
564
+ const own: readonly [string, string][] = [
565
+ ["color", "EDGE_STROKE_UNSELECTED_PAINT"],
566
+ ["sourceArrowColor", "EDGE_SOURCE_ARROW_UNSELECTED_PAINT"],
567
+ ["targetArrowColor", "EDGE_TARGET_ARROW_UNSELECTED_PAINT"],
568
+ ["sourceArrowColor", "EDGE_SOURCE_ARROW_COLOR"],
569
+ ["targetArrowColor", "EDGE_TARGET_ARROW_COLOR"],
570
+ ];
571
+ for (const [prop, vp] of own) {
572
+ out[prop] = (out[prop] ?? []).map((v, i) => {
573
+ const b = bypass(i, vp);
574
+ const site = { notes, target, property: prop, element: i };
575
+ return (b === undefined || b === null ? null : colorParser(b, site)) ?? v;
576
+ });
577
+ }
365
578
  }
366
579
  noteUncarried(target, s, used, bypassed, notes);
367
- fillToolDefaults(target, out, n, options.defaults ?? null);
368
580
  if (target === "edge") {
369
- straightenBendless(out, one);
581
+ const bends = column(EDGE_BEND_VP, bendsParser, "bends");
582
+ if (bends.some((v) => v !== null)) {
583
+ out.bends = bends;
584
+ }
585
+ // before the tool's defaults: an edge the style leaves unset is curved as Cytoscape's EDGE_CURVED default is
586
+ const curvedAsSet = out.curved?.slice();
587
+ straightenBendless(out, one, n, elements.ends);
588
+ loopHandles(out, one, curvedAsSet, elements.ends);
589
+ arrowProportions(out, column);
370
590
  }
591
+ fillToolDefaults(target, out, n, options.defaults ?? null);
371
592
  return out;
372
593
  }
373
594
 
374
595
  /**
375
- * Marks straight every curved edge without bends: `EDGE_CURVED` only rounds the bends an edge has.
596
+ * A visual property's value as written, a CX2 object as its JSON.
597
+ * @param v - the value
598
+ * @returns its text, or null
599
+ */
600
+ const rawText: CytoscapeValueParser = (v) => {
601
+ if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
602
+ return String(v);
603
+ }
604
+ return typeof v === "object" && v !== null ? JSON.stringify(v) : null;
605
+ };
606
+
607
+ /**
608
+ * Reads what Cytoscape draws of each element's label beyond its words, font and color: the box behind it (drawn only
609
+ * with a `*_LABEL_BACKGROUND_SHAPE` other than NONE, the default, in its color and transparency), where it is placed
610
+ * (`*_LABEL_POSITION` read whole: which point of the label's box is pinned to which point of the node, or of the
611
+ * edge's line, and the offset) and how its lines are justified. Each column is kept only where some element needs it;
612
+ * an edge's place is kept whenever it has one, since Cytoscape centers an edge's label on its line.
613
+ * @param target - nodes or edges
614
+ * @param out - the values per property, changed in place
615
+ * @param one - reads one visual property of one element
616
+ * @param n - the element count
617
+ * @param ends - the edges' ends and their nodes' centers, when known
618
+ */
619
+ function labelDress(
620
+ target: StyleTarget,
621
+ out: Partial<Record<string, StyleColumn>>,
622
+ one: Resolver["one"],
623
+ n: number,
624
+ ends: CytoscapeElements["ends"],
625
+ ): void {
626
+ const vp = (name: string): string => `${target === "node" ? "NODE" : "EDGE"}_LABEL_${name}`;
627
+ const columns: Record<string, (StyleValue | null)[]> = {};
628
+ const put = (property: string, i: number, v: StyleValue | null): void => {
629
+ let column = columns[property];
630
+ if (column === undefined) {
631
+ column = new Array<StyleValue | null>(n).fill(null);
632
+ columns[property] = column;
633
+ }
634
+ column[i] = v;
635
+ };
636
+ for (let i = 0; i < n; i++) {
637
+ labelBox(vp, one, i, put);
638
+ // read whole, quietly (the lexicon's reading of the same value notes a bad one), under a name of its own: a
639
+ // mapping is parsed once per visual property and neutral property
640
+ const placed = one(vp("POSITION"), rawText, "labelPlace", i);
641
+ const raw = typeof placed === "string" && placed.startsWith("{") ? (JSON.parse(placed) as unknown) : placed;
642
+ const place = cytoscapeLabelPlace(raw, { notes: new StyleNotes(), target, property: "labelPosition" });
643
+ if (place !== null) {
644
+ placeLabel(target, place, i, out, put, ends);
645
+ }
646
+ if (target === "edge") {
647
+ autorotate(one, i, out, n, ends);
648
+ }
649
+ }
650
+ const kept = (property: string, v: StyleValue | null): boolean =>
651
+ v !== null && v !== 0 && (v !== "center" || (property === "labelPosition" && target === "edge"));
652
+ for (const [property, values] of Object.entries(columns)) {
653
+ if (values.some((v) => kept(property, v))) {
654
+ out[property] = values;
655
+ }
656
+ }
657
+ }
658
+
659
+ /**
660
+ * The box Cytoscape draws behind one label, when its shape is not NONE: its color (`#B6B6B6` unset, the lexicon's
661
+ * default), its opacity, and for ROUND_RECTANGLE its corners, rounded an eighth of the box's height: 1.455 on the
662
+ * 11.64-tall box of a 10 px label (xgmml-specimen-labels.svg, label-background-shape-round-rectangle), so 0.1455 of the
663
+ * label's size. ponytail: one line's height; a box of several lines is rounded as one line's.
664
+ * @param vp - names a label visual property of the target
665
+ * @param one - reads one visual property of one element
666
+ * @param i - the element
667
+ * @param put - sets one element's value of a property
668
+ */
669
+ function labelBox(
670
+ vp: (name: string) => string,
671
+ one: Resolver["one"],
672
+ i: number,
673
+ put: (property: string, i: number, v: StyleValue | null) => void,
674
+ ): void {
675
+ const shape = one(vp("BACKGROUND_SHAPE"), rawText, "labelBackgroundShape", i);
676
+ if (typeof shape !== "string" || shape.trim().toUpperCase() === "NONE") {
677
+ return;
678
+ }
679
+ put("labelBackground", i, one(vp("BACKGROUND_COLOR"), colorParser, "labelBackground", i) ?? "#b6b6b6");
680
+ const [t, o] = [vp("BACKGROUND_TRANSPARENCY"), vp("BACKGROUND_OPACITY")];
681
+ const opacity =
682
+ one(t, opacityParser(t), "labelBackgroundOpacity", i) ?? one(o, opacityParser(o), "labelBackgroundOpacity", i);
683
+ put("labelBackgroundOpacity", i, opacity ?? 1);
684
+ // CX2 spells it round-rectangle
685
+ if (shape.trim().toUpperCase().replace("-", "_") === "ROUND_RECTANGLE") {
686
+ const size = one(vp("FONT_SIZE"), sizeParser, "labelSize", i);
687
+ // desktop's default label sizes: 12 on a node, 10 on an edge
688
+ const defaultSize = vp("FONT_SIZE").startsWith("EDGE") ? 10 : 12;
689
+ put("labelCornerRadius", i, num6(LABEL_CORNER_PER_SIZE * (typeof size === "number" ? size : defaultSize)));
690
+ }
691
+ }
692
+
693
+ /** How far Cytoscape rounds a ROUND_RECTANGLE label box's corners, as a fraction of the label's font size. */
694
+ const LABEL_CORNER_PER_SIZE = 0.1455;
695
+
696
+ /**
697
+ * Where one label is placed, from its Cytoscape label position: its neutral `labelPosition`, offsets, shifts and
698
+ * line justification. A node's label is pinned against the node's box. An edge's is pinned to a point of its drawn
699
+ * line, the middle unless the anchor's horizontal letter names an end (W the source's, E the target's; its vertical
700
+ * letter changes nothing, measured on Cytoscape 3.10.5's SVG), from the line's middle, where it is centered.
701
+ * @param target - nodes or edges
702
+ * @param place - the label position
703
+ * @param i - the element
704
+ * @param out - the values per property (the node sizes are read)
705
+ * @param put - sets one element's value of a property
706
+ * @param ends - the edges' ends and their nodes' centers, when known
707
+ */
708
+ function placeLabel(
709
+ target: StyleTarget,
710
+ place: CytoscapeLabelPlace,
711
+ i: number,
712
+ out: Partial<Record<string, StyleColumn>>,
713
+ put: (property: string, i: number, v: StyleValue | null) => void,
714
+ ends: CytoscapeElements["ends"],
715
+ ): void {
716
+ let move: ReturnType<typeof cytoscapeLabelMove>;
717
+ if (target === "node") {
718
+ const [w, h] = [out.width?.[i], out.height?.[i]];
719
+ move = cytoscapeLabelMove(place, typeof w === "number" ? w : 0, typeof h === "number" ? h : 0);
720
+ put("labelPosition", i, cytoscapeLabelBase(place));
721
+ } else {
722
+ const [ax, ay] = lineEnd(ends, i, place.node[0]);
723
+ move = {
724
+ offset: [ax + place.offset[0], ay + place.offset[1]],
725
+ shift: [halfBack(place.label[0]), halfBack(place.label[1])],
726
+ };
727
+ put("labelPosition", i, "center");
728
+ }
729
+ put("labelOffsetX", i, num6(move.offset[0]));
730
+ put("labelOffsetY", i, num6(move.offset[1]));
731
+ put("labelShiftX", i, move.shift[0]);
732
+ put("labelShiftY", i, move.shift[1]);
733
+ put("labelTextAlign", i, place.justify);
734
+ }
735
+
736
+ /**
737
+ * Turns an edge's label along its line under `EDGE_LABEL_AUTOROTATE`, as Cytoscape draws it: the line's angle from
738
+ * its source's center to its target's (kept between -90 and 90 so the words read left to right), plus its
739
+ * `EDGE_LABEL_ROTATION`.
740
+ * ponytail: the angle is the file's node places at import; a layout that moves the nodes leaves it as it was, until
741
+ * the neutral styles can say "along the line"
742
+ * @param one - reads one visual property of one element
743
+ * @param e - the edge
744
+ * @param out - the values per property, changed in place
745
+ * @param n - the edge count
746
+ * @param ends - the edges' ends and their nodes' centers
747
+ */
748
+ function autorotate(
749
+ one: Resolver["one"],
750
+ e: number,
751
+ out: Partial<Record<string, StyleColumn>>,
752
+ n: number,
753
+ ends: CytoscapeElements["ends"],
754
+ ): void {
755
+ const on = one(AUTOROTATE_VP, rawText, "labelRotation", e);
756
+ const [si, ti] = [ends?.source[e], ends?.target[e]];
757
+ const [s, t] = [si === undefined ? null : ends?.nodeAt?.[si], ti === undefined ? null : ends?.nodeAt?.[ti]];
758
+ if (String(on).toLowerCase() !== "true" || !s || !t || (s[0] === t[0] && s[1] === t[1])) {
759
+ return;
760
+ }
761
+ const a = (Math.atan2(t[1] - s[1], t[0] - s[0]) * 180) / Math.PI;
762
+ let upright = a;
763
+ if (a > 90) {
764
+ upright = a - 180;
765
+ } else if (a <= -90) {
766
+ upright = a + 180;
767
+ }
768
+ out.labelRotation ??= new Array<StyleValue | null>(n).fill(null);
769
+ const column = out.labelRotation as (StyleValue | null)[];
770
+ const own = column[e];
771
+ column[e] = num6((((upright + (typeof own === "number" ? own : 0)) % 360) + 360) % 360);
772
+ }
773
+
774
+ /**
775
+ * How far from the middle of an edge's drawn line one of its ends is, on screen (y down): the line between its two
776
+ * nodes' centers, cut where it meets each node's ellipse; 0 for the middle, or where the centers are not known.
777
+ * @param ends - the edges' ends, their nodes' centers and boxes
778
+ * @param e - the edge
779
+ * @param side - -1 for the source's end, 1 for the target's, 0 for the middle
780
+ * @returns the offset from the line's middle
781
+ */
782
+ function lineEnd(ends: CytoscapeElements["ends"], e: number, side: number): readonly [number, number] {
783
+ const [si, ti] = [ends?.source[e], ends?.target[e]];
784
+ const [s, t] = [si === undefined ? null : ends?.nodeAt?.[si], ti === undefined ? null : ends?.nodeAt?.[ti]];
785
+ if (side === 0 || s === null || s === undefined || t === null || t === undefined) {
786
+ return [0, 0];
787
+ }
788
+ const length = Math.hypot(t[0] - s[0], t[1] - s[1]);
789
+ if (length === 0) {
790
+ return [0, 0];
791
+ }
792
+ const [ux, uy] = [(t[0] - s[0]) / length, (t[1] - s[1]) / length];
793
+ // where the line leaves a node's ellipse, along it from the center
794
+ const reach = (node: number | undefined): number => {
795
+ const box = node === undefined ? null : ends?.nodeBox?.[node];
796
+ if (box === null || box === undefined) {
797
+ return 0;
798
+ }
799
+ const [a, b] = [box[0] / 2, box[1] / 2];
800
+ return a === 0 || b === 0 ? 0 : (a * b) / Math.hypot(b * ux, a * uy);
801
+ };
802
+ const from = reach(si);
803
+ const to = length - reach(ti);
804
+ // the drawn line's middle and the end asked for, both measured along the line from the source's center
805
+ const along = (side < 0 ? from : to) - (from + to) / 2;
806
+ return [ux * along, uy * along];
807
+ }
808
+
809
+ /** How tall a regular hexagon is for its width. */
810
+ const HEXAGON_ASPECT = Math.sqrt(3) / 2;
811
+
812
+ /**
813
+ * Gives every hexagon node the height Cytoscape desktop draws it at. Its HEXAGON is a regular hexagon squashed to
814
+ * the node's box rather than one filling it: the corners reach the box's sides, the flat top and bottom only
815
+ * `sqrt(3) / 2` of the way up and down, so a 40 x 40 node with a border of 1 is a 39 x 33.8 path (its border is
816
+ * inside its size, `borderPosition` inside). The neutral hexagon fills its box, so the node is that much shorter.
817
+ * @param out - the node values per property, changed in place
818
+ */
819
+ function squashHexagons(out: Partial<Record<string, StyleColumn>>): void {
820
+ const { shape, height } = out;
821
+ if (shape === undefined || height === undefined || !shape.includes("hexagon")) {
822
+ return;
823
+ }
824
+ const border = out.borderWidth;
825
+ out.height = height.map((h, i) => {
826
+ if (shape[i] !== "hexagon" || typeof h !== "number") {
827
+ return h;
828
+ }
829
+ const b = border?.[i];
830
+ const w = typeof b === "number" ? Math.min(b, h) : 0;
831
+ return (h - w) * HEXAGON_ASPECT + w;
832
+ });
833
+ }
834
+
835
+ /**
836
+ * What Cytoscape draws of each end's arrow beyond its shape and the one neutral `arrowSize`: the source end's own
837
+ * size where it differs from the target's (an unset size is Cytoscape's 6), and the length and width of the short and
838
+ * crossed arrows against their neutral shape's, and how far off its node each arrow stands. Each is kept only where
839
+ * some edge needs it.
840
+ * @param out - the values per property, changed in place
841
+ * @param column - reads one visual property of every element
842
+ */
843
+ function arrowProportions(
844
+ out: Partial<Record<string, StyleColumn>>,
845
+ column: (vp: string, parse: CytoscapeValueParser, property: string) => (StyleValue | null)[],
846
+ ): void {
847
+ const size = out.arrowSize;
848
+ const own = column("EDGE_SOURCE_ARROW_SIZE", arrowSizeParser, "sourceArrowSize").map((v) => v ?? 1);
849
+ if (own.some((v, i) => v !== (size?.[i] ?? 1))) {
850
+ out.sourceArrowSize = own;
851
+ }
852
+ for (const [prop, vp, side] of [
853
+ ["sourceArrowLength", "EDGE_SOURCE_ARROW_SHAPE", "length"],
854
+ ["targetArrowLength", "EDGE_TARGET_ARROW_SHAPE", "length"],
855
+ ["sourceArrowWidth", "EDGE_SOURCE_ARROW_SHAPE", "width"],
856
+ ["targetArrowWidth", "EDGE_TARGET_ARROW_SHAPE", "width"],
857
+ ] as const) {
858
+ const values = column(vp, arrowProportion(side), prop).map((v) => (v === 1 ? null : v));
859
+ if (values.some((v) => v !== null)) {
860
+ out[prop] = values;
861
+ }
862
+ }
863
+ // the arrows desktop draws standing off their node (T, the half circles, HALF_TOP, the squares)
864
+ for (const [prop, vp] of [
865
+ ["sourceArrowGap", "EDGE_SOURCE_ARROW_SHAPE"],
866
+ ["targetArrowGap", "EDGE_TARGET_ARROW_SHAPE"],
867
+ ] as const) {
868
+ const values = column(vp, arrowGap, prop).map((v) => (v === 0 ? null : v));
869
+ if (values.some((v) => v !== null)) {
870
+ out[prop] = values;
871
+ }
872
+ }
873
+ }
874
+
875
+ /**
876
+ * Marks straight every curved edge without bends, except where Cytoscape desktop fans it: `EDGE_CURVED` only
877
+ * rounds the bends an edge has, and the bends Cytoscape adds itself. Among the edges joining the same two nodes
878
+ * (either way round, not loops), it draws the last it created straight and bends each earlier one without bends
879
+ * of its own round an anchor beside the line (`DEdgeDetails.getAnchors`, `EDGE_STACKING` `AUTO_BEND`, the default;
880
+ * it walks the pair's edges newest first, measured on Cytoscape 3.10.5's SVG of edges joining two nodes both ways)
881
+ * -- unless the last has bends, when every anchor falls on the line. Its anchors are the larger side of the two
882
+ * nodes times twice `EDGE_STACKING_DENSITY` apart, so the curves' middles half that: each fanned edge's
883
+ * `fanSpacing`, when the node sizes are known. A fanned edge is drawn curved even under `EDGE_CURVED` false, and an
884
+ * edge whose `EDGE_STACKING` is HAYSTACK is neither fanned nor counted: desktop draws it straight (both measured on
885
+ * Cytoscape 3.10.5's SVG of the edges-lines specimen sheet).
886
+ * @param out - the values per property, changed in place
887
+ * @param one - reads one visual property of one element
888
+ * @param n - the edge count
889
+ * @param ends - each edge's source and target node index, in creation order, when known
890
+ */
891
+ function straightenBendless(
892
+ out: Partial<Record<string, StyleColumn>>,
893
+ one: Resolver["one"],
894
+ n: number,
895
+ ends: CytoscapeElements["ends"],
896
+ ): void {
897
+ // an edge the style leaves unset takes EDGE_CURVED's default, true
898
+ const curved = out.curved ?? new Array<StyleValue | null>(n).fill(null);
899
+ const bent = (i: number): boolean => one(EDGE_BEND_VP, bendParser, "curved", i) === true;
900
+ const haystack = (i: number): boolean =>
901
+ String(one(EDGE_STACKING_VP, rawText, "fanned", i) ?? "").toUpperCase() === "HAYSTACK";
902
+ // each fanned edge's place in its pair's walk (1 for the first fanned)
903
+ const place = ends === undefined ? new Map<number, number>() : fanPlaces(ends, curved.length, bent, haystack);
904
+ const fanned = new Set(place.keys());
905
+ const rounds = (i: number): boolean => fanned.has(i) || bent(i);
906
+ const rounded = curved.map((c, i) => {
907
+ if (c === null) {
908
+ return rounds(i) ? true : null;
909
+ }
910
+ return c === true || fanned.has(i) ? rounds(i) : c;
911
+ });
912
+ if (out.curved !== undefined || rounded.includes(true)) {
913
+ out.curved = rounded;
914
+ }
915
+ if (ends?.nodeSize === undefined || fanned.size === 0) {
916
+ return;
917
+ }
918
+ const { source, target, nodeSize } = ends;
919
+ out.fanSpacing = curved.map((_, i) => {
920
+ const size = Math.max(nodeSize[source[i]] ?? Number.NaN, nodeSize[target[i]] ?? Number.NaN);
921
+ if (out.curved?.[i] !== true || !fanned.has(i) || bent(i) || !Number.isFinite(size)) {
922
+ return null;
923
+ }
924
+ const read = one(EDGE_STACKING_DENSITY_VP, sizeParser, "fanSpacing", i);
925
+ const density = Math.min(1, typeof read === "number" ? read : EDGE_STACKING_DENSITY_DEFAULT);
926
+ return size * density;
927
+ });
928
+ fanAnchors(out, ends, place);
929
+ }
930
+
931
+ /**
932
+ * The edges desktop fans, each with its place in its node pair's walk (1 for the first fanned). Desktop walks a node
933
+ * pair's edges newest first (its adjacency lists take each new edge at the head); the first it meets is drawn
934
+ * straight, and each later one fanned unless that first one has bends. Loops and haystack edges are left out.
935
+ * @param ends - each edge's source and target node index, and the order they were created in
936
+ * @param count - the edge count
937
+ * @param bent - whether an edge has bends of its own
938
+ * @param haystack - whether an edge is a haystack edge
939
+ * @returns each fanned edge's place, in walk order
940
+ */
941
+ function fanPlaces(
942
+ ends: NonNullable<CytoscapeElements["ends"]>,
943
+ count: number,
944
+ bent: (i: number) => boolean,
945
+ haystack: (i: number) => boolean,
946
+ ): Map<number, number> {
947
+ const place = new Map<number, number>();
948
+ const first = new Map<string, { f: number; k: number }>();
949
+ for (const i of newestFirst(count, ends.created?.edge)) {
950
+ const [s, t] = [ends.source[i], ends.target[i]];
951
+ if (s === t || haystack(i)) {
952
+ continue;
953
+ }
954
+ const key = `${Math.min(s, t)},${Math.max(s, t)}`;
955
+ const f = first.get(key);
956
+ if (f === undefined) {
957
+ first.set(key, { f: i, k: 0 });
958
+ } else if (!bent(f.f)) {
959
+ f.k++;
960
+ place.set(i, f.k);
961
+ }
962
+ }
963
+ return place;
964
+ }
965
+
966
+ /**
967
+ * The edges newest first: by the order they were created in when it is known, else last index first.
968
+ * @param count - the edge count
969
+ * @param created - each edge's place in the creation order, when known
970
+ * @returns the edge indices in that order
971
+ */
972
+ function newestFirst(count: number, created: ArrayLike<number> | undefined): number[] {
973
+ const walk = Array.from({ length: count }, (_, i) => i);
974
+ walk.sort(created === undefined ? (a, b) => b - a : (a, b) => created[b] - created[a]);
975
+ return walk;
976
+ }
977
+
978
+ /**
979
+ * Gives each fanned edge its place in desktop's fan as a bend, when the order desktop created the nodes in is known:
980
+ * the fan's side is then desktop's, not graphty's. Desktop measures each pair's fan from the node whose view it made
981
+ * first, and it makes views newest node first (`DEdgeDetails.getAnchors`: the pair's lower view SUID is its source;
982
+ * `SimpleNetwork.getNodeList` lists the newest node first); the `k`-th fanned edge bows `ceil(k / 2)` fan spacings
983
+ * off the middle of the line, to the right of the fan's direction (y down) for odd `k`, to the left for even. The
984
+ * bend is the control point of a quadratic Bezier whose middle lies there, twice as far off.
985
+ * @param out - the values per property, with `fanSpacing` set; changed in place
986
+ * @param ends - the edges' ends, their nodes' centers and creation order
987
+ * @param place - each fanned edge's place in its pair's walk, from 1
988
+ */
989
+ function fanAnchors(
990
+ out: Partial<Record<string, StyleColumn>>,
991
+ ends: NonNullable<CytoscapeElements["ends"]>,
992
+ place: ReadonlyMap<number, number>,
993
+ ): void {
994
+ const { created, nodeAt, source, target } = ends;
995
+ const spacing = out.fanSpacing?.slice();
996
+ if (created === undefined || nodeAt === undefined || spacing === undefined) {
997
+ return;
998
+ }
999
+ const bends = out.bends?.slice() ?? new Array<StyleValue | null>(source.length).fill(null);
1000
+ const bendCurve = out.bendCurve?.slice() ?? new Array<StyleValue | null>(source.length).fill(null);
1001
+ let changed = false;
1002
+ for (const [i, k] of place) {
1003
+ const [s, t] = [source[i], target[i]];
1004
+ const [ps, pt, f] = [nodeAt[s], nodeAt[t], spacing[i]];
1005
+ if (ps === null || ps === undefined || pt === null || pt === undefined || typeof f !== "number") {
1006
+ continue;
1007
+ }
1008
+ const len = Math.hypot(pt[0] - ps[0], pt[1] - ps[1]);
1009
+ if (len === 0) {
1010
+ continue;
1011
+ }
1012
+ // the fan's direction: from the node desktop made a view of first, the one created last
1013
+ const sign = created.node[s] > created.node[t] ? 1 : -1;
1014
+ const [nx, ny] = [(sign * (pt[0] - ps[0])) / len, (sign * (pt[1] - ps[1])) / len];
1015
+ const offset = Math.ceil(k / 2) * (k % 2 === 0 ? 1 : -1) * 2 * f;
1016
+ const [vx, vy] = [offset * ny, -offset * nx];
1017
+ // to the left of source -> target, y up, as a fraction of the length
1018
+ const across = (vx * (pt[1] - ps[1]) - vy * (pt[0] - ps[0])) / (len * len);
1019
+ bends[i] = `0.5,${String(Math.round(across * 1e6) / 1e6 || 0)}`;
1020
+ bendCurve[i] = "bezier";
1021
+ spacing[i] = null;
1022
+ changed = true;
1023
+ }
1024
+ if (changed) {
1025
+ out.bends = bends;
1026
+ out.bendCurve = bendCurve;
1027
+ out.fanSpacing = spacing;
1028
+ }
1029
+ }
1030
+
1031
+ /**
1032
+ * Gives each self-loop without bends of its own the two handles Cytoscape desktop draws it round
1033
+ * (`DEdgeDetails.getAnchors`): one left of the node's center and one above it, each `(i + 3) / 2` of the node's
1034
+ * size times twice `EDGE_STACKING_DENSITY` away, where the size is the larger side of the node with its border
1035
+ * (its extents in desktop's spatial index) and `i` counts the node's earlier loops without bends, newest first as
1036
+ * desktop walks them. A loop is curved through them unless `EDGE_CURVED` says false. Measured on Cytoscape
1037
+ * 3.10.5's SVG of the edges-lines specimen sheet (within 0.3 px of its loops).
376
1038
  * @param out - the values per property, changed in place
377
1039
  * @param one - reads one visual property of one element
1040
+ * @param curvedAsSet - each edge's `curved` as the style set it, before bendless edges were straightened
1041
+ * @param ends - each edge's source and target node index, in creation order, and each node's box, when known
378
1042
  */
379
- function straightenBendless(out: Partial<Record<string, StyleColumn>>, one: Resolver["one"]): void {
380
- const { curved } = out;
381
- if (curved !== undefined) {
382
- out.curved = curved.map((c, i) => (c === true ? one(EDGE_BEND_VP, bendParser, "curved", i) === true : c));
1043
+ function loopHandles(
1044
+ out: Partial<Record<string, StyleColumn>>,
1045
+ one: Resolver["one"],
1046
+ curvedAsSet: readonly (StyleValue | null)[] | undefined,
1047
+ ends: CytoscapeElements["ends"],
1048
+ ): void {
1049
+ const box = ends?.nodeBox;
1050
+ if (ends === undefined || box === undefined) {
1051
+ return;
1052
+ }
1053
+ const bends = out.bends?.slice() ?? new Array<StyleValue | null>(ends.source.length).fill(null);
1054
+ const curved = out.curved?.slice() ?? new Array<StyleValue | null>(ends.source.length).fill(null);
1055
+ const earlier = new Map<number, number>();
1056
+ const fraction = (v: number): string => String(Math.round(v * 1e4) / 1e4 || 0);
1057
+ let changed = false;
1058
+ for (let i = ends.source.length - 1; i >= 0; i--) {
1059
+ const node = ends.source[i];
1060
+ const b = box[node];
1061
+ if (node !== ends.target[i] || bends[i] !== null) {
1062
+ continue;
1063
+ }
1064
+ const rank = earlier.get(node) ?? 0;
1065
+ earlier.set(node, rank + 1);
1066
+ if (b === null || b === undefined || b[0] <= 0 || b[1] <= 0) {
1067
+ continue;
1068
+ }
1069
+ const read = one(EDGE_STACKING_DENSITY_VP, sizeParser, "fanSpacing", i);
1070
+ const density = Math.min(1, typeof read === "number" ? read : EDGE_STACKING_DENSITY_DEFAULT);
1071
+ const reach = (((rank + 3) * (Math.max(b[0], b[1]) + b[2])) / 2) * 2 * density;
1072
+ // as `x,y` fractions of the node's half width and half height, y up: left of the center, then above it
1073
+ bends[i] = `${fraction(-reach / (b[0] / 2))},0 0,${fraction(reach / (b[1] / 2))}`;
1074
+ curved[i] = curvedAsSet?.[i] !== false;
1075
+ changed = true;
1076
+ }
1077
+ if (changed) {
1078
+ out.bends = bends;
1079
+ out.curved = curved;
383
1080
  }
384
1081
  }
385
1082
 
@@ -399,6 +1096,41 @@ export const bendParser: CytoscapeValueParser = (raw) => {
399
1096
  return Array.isArray(raw) ? raw.length > 0 : raw !== null && raw !== undefined && typeof raw === "object";
400
1097
  };
401
1098
 
1099
+ /**
1100
+ * An `EDGE_BEND` value as the neutral `bends`: Cytoscape keeps each handle as `cos,sin,ratio`, the handle at the
1101
+ * source center plus `ratio` times the source-to-target vector turned by the angle (y down), handles separated by
1102
+ * `|`. Relative to the same line, y up, that is `ratio * cos` along it and `-ratio * sin` across it.
1103
+ * @param input - the value: an `EDGE_BEND` text, or CX2's `EDGE_CONTROL_POINTS` objects
1104
+ * @param site - where it was read
1105
+ * @returns the bends, or null for an edge without handles or a value that is not handles
1106
+ */
1107
+ const bendsParser: CytoscapeValueParser = (input, site) => {
1108
+ // CX2's EDGE_CONTROL_POINTS: one object per handle, whose `sin` Cytoscape fills with EDGE_BEND's first number and
1109
+ // `cos` with its second (it reads them back the same way: specimen-edges-lines bend-one-handle bends)
1110
+ const raw = Array.isArray(input)
1111
+ ? input
1112
+ .map((h: unknown) => {
1113
+ const o = (h ?? {}) as Record<string, unknown>;
1114
+ return `${Number(o.sin)},${Number(o.cos)},${Number(o.ratio)}`;
1115
+ })
1116
+ .join("|")
1117
+ : input;
1118
+ if (typeof raw !== "string" || !bendParser(raw, site)) {
1119
+ return null;
1120
+ }
1121
+ const points: string[] = [];
1122
+ for (const handle of raw.trim().split("|")) {
1123
+ const [c, sin, ratio] = handle.split(",").map((t) => Number(t.trim()));
1124
+ if (![c, sin, ratio].every((v) => Number.isFinite(v))) {
1125
+ noteAt(site, STYLE_ISSUE.BAD_VALUE, raw.slice(0, 64));
1126
+ return null;
1127
+ }
1128
+ const fraction = (v: number): string => String(Math.round(v * 1e4) / 1e4 || 0);
1129
+ points.push(`${fraction(ratio * c)},${fraction(-ratio * sin)}`);
1130
+ }
1131
+ return points.join(" ");
1132
+ };
1133
+
402
1134
  /** Default values that mean "nothing drawn": a VP left at one of these is not worth a note. */
403
1135
  const INERT_DEFAULT = /NullCustomGraphics|^255$|^0(?:\.0+)?$|^$|^C,C,c,0\.00,0\.00$|^false$/;
404
1136
 
@@ -494,7 +1226,15 @@ export function resolveCytoscapeBypasses(
494
1226
  ): Partial<Record<string, StyleColumn>> {
495
1227
  const notes = options.notes ?? new StyleNotes();
496
1228
  const style = emptyCytoscapeStyle();
497
- const elements: CytoscapeElements = { count: maps.length, value: () => null, bypasses: maps };
1229
+ const elements: CytoscapeElements = {
1230
+ count: maps.length,
1231
+ value: options.value ?? (() => null),
1232
+ // Cytoscape 3.10.5 draws an XGMML edge's EDGE_LABEL_AUTOROTATE true level, where it turns the same edge read
1233
+ // from CX, CX2 or a session along its line (the label-autorotate-true edge of the edge-labels and
1234
+ // mappings-bypass-p13 sheets in its SVG): its XGMML reader does not apply it, so neither does graph-io
1235
+ bypasses: maps.map((m) => (m?.has(AUTOROTATE_VP) === true ? withoutKey(m, AUTOROTATE_VP) : m)),
1236
+ ends: options.ends,
1237
+ };
498
1238
  const out = resolveCytoscape(target, style, elements, { notes, budget: options.budget });
499
1239
  if (target === "node" && out.width === undefined) {
500
1240
  const size = maps.map((m) => {