@graphty/graph-io 0.3.48 → 0.3.50

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 (600) hide show
  1. package/dist/chunks/{approximations-C2riR4NT.js → approximations-BRXsll0T.js} +2 -2
  2. package/dist/chunks/{approximations-C2riR4NT.js.map → approximations-BRXsll0T.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-Cu22ewuS.js → block-yl0f_qLO.js} +931 -164
  6. package/dist/chunks/block-yl0f_qLO.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-CV_Bhcyi.js → codes-BE2xir2k.js} +6 -2
  10. package/dist/chunks/codes-BE2xir2k.js.map +1 -0
  11. package/dist/chunks/{constants-D0LqcsLJ.js → constants-CKkYLPtt.js} +2 -2
  12. package/dist/chunks/{constants-D0LqcsLJ.js.map → constants-CKkYLPtt.js.map} +1 -1
  13. package/dist/chunks/{context-cgmmOxZ2.js → context-DizmppHy.js} +5 -4
  14. package/dist/chunks/{context-cgmmOxZ2.js.map → context-DizmppHy.js.map} +1 -1
  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-BiQsnMTb.js → credentials-CmvJXYeH.js} +67 -16
  18. package/dist/chunks/credentials-CmvJXYeH.js.map +1 -0
  19. package/dist/chunks/{cx-export-BEeF6ymo.js → cx-export-Bt6NoqTQ.js} +3 -3
  20. package/dist/chunks/{cx-export-BEeF6ymo.js.map → cx-export-Bt6NoqTQ.js.map} +1 -1
  21. package/dist/chunks/descriptor-B28U25x4.js +60 -0
  22. package/dist/chunks/descriptor-B28U25x4.js.map +1 -0
  23. package/dist/chunks/{descriptor-BJ-W0Jd-.js → descriptor-Dhez_Cew.js} +11 -2
  24. package/dist/chunks/descriptor-Dhez_Cew.js.map +1 -0
  25. package/dist/chunks/{emit-CD8xnY8s.js → emit-7Jkpg0yd.js} +1788 -133
  26. package/dist/chunks/emit-7Jkpg0yd.js.map +1 -0
  27. package/dist/chunks/{escape-DH2Egt-l.js → escape-CuCIzNMB.js} +8 -8
  28. package/dist/chunks/{escape-DH2Egt-l.js.map → escape-CuCIzNMB.js.map} +1 -1
  29. package/dist/chunks/{export-CZ7VRm4I.js → export-Cha4dRFz.js} +45 -387
  30. package/dist/chunks/export-Cha4dRFz.js.map +1 -0
  31. package/dist/chunks/{exporter-ChjL5fmP.js → exporter-1Ajud15J.js} +9 -8
  32. package/dist/chunks/{exporter-ChjL5fmP.js.map → exporter-1Ajud15J.js.map} +1 -1
  33. package/dist/chunks/{exporter-BIdaoIgh.js → exporter-B6yvL3wy.js} +7 -7
  34. package/dist/chunks/{exporter-BIdaoIgh.js.map → exporter-B6yvL3wy.js.map} +1 -1
  35. package/dist/chunks/{exporter-Dcw7Ldtq.js → exporter-BP6otMO6.js} +6 -6
  36. package/dist/chunks/{exporter-Dcw7Ldtq.js.map → exporter-BP6otMO6.js.map} +1 -1
  37. package/dist/chunks/{exporter-DtVU80Fa.js → exporter-CA5q8ROP.js} +9 -8
  38. package/dist/chunks/{exporter-DtVU80Fa.js.map → exporter-CA5q8ROP.js.map} +1 -1
  39. package/dist/chunks/{exporter-bxxjOrDZ.js → exporter-CQQZFJ2v.js} +1284 -156
  40. package/dist/chunks/exporter-CQQZFJ2v.js.map +1 -0
  41. package/dist/chunks/format-BXiAb-1h.js +408 -0
  42. package/dist/chunks/format-BXiAb-1h.js.map +1 -0
  43. package/dist/chunks/{generic-CP6YD34u.js → generic-Dc21MAdg.js} +387 -31
  44. package/dist/chunks/generic-Dc21MAdg.js.map +1 -0
  45. package/dist/chunks/{importer-B87_fmVx.js → importer-C6NVpCXp.js} +327 -84
  46. package/dist/chunks/importer-C6NVpCXp.js.map +1 -0
  47. package/dist/chunks/{importer-DPZDN40-.js → importer-CKFe4q54.js} +25 -17
  48. package/dist/chunks/importer-CKFe4q54.js.map +1 -0
  49. package/dist/chunks/{importer-Bji2MeWr.js → importer-CKbUbsJA.js} +13 -10
  50. package/dist/chunks/{importer-Bji2MeWr.js.map → importer-CKbUbsJA.js.map} +1 -1
  51. package/dist/chunks/{importer-CB_zV5_L.js → importer-ClCsdgTJ.js} +208 -1104
  52. package/dist/chunks/importer-ClCsdgTJ.js.map +1 -0
  53. package/dist/chunks/{importer-e3huMZbm.js → importer-CyVZTrf0.js} +14 -10
  54. package/dist/chunks/importer-CyVZTrf0.js.map +1 -0
  55. package/dist/chunks/{importer-CVT-JyDE.js → importer-DgG4v1Ms.js} +1537 -355
  56. package/dist/chunks/importer-DgG4v1Ms.js.map +1 -0
  57. package/dist/chunks/{importer-Cyy6UseH.js → importer-asFUrIsj.js} +66 -13
  58. package/dist/chunks/importer-asFUrIsj.js.map +1 -0
  59. package/dist/chunks/{input-Ccg9I22A.js → input-CAxt_aV-.js} +4 -4
  60. package/dist/chunks/{input-Ccg9I22A.js.map → input-CAxt_aV-.js.map} +1 -1
  61. package/dist/chunks/{json-elements-By172SVq.js → json-elements-Cq76WjnZ.js} +4 -4
  62. package/dist/chunks/{json-elements-By172SVq.js.map → json-elements-Cq76WjnZ.js.map} +1 -1
  63. package/dist/chunks/{lexicon-u2SI5xcx.js → lexicon-IVRq2Uoo.js} +282 -74
  64. package/dist/chunks/lexicon-IVRq2Uoo.js.map +1 -0
  65. package/dist/chunks/{ontology-export-BwgMyuF0.js → ontology-export-OMo91mb0.js} +4 -4
  66. package/dist/chunks/{ontology-export-BwgMyuF0.js.map → ontology-export-OMo91mb0.js.map} +1 -1
  67. package/dist/chunks/{records-Cgvxz-Vx.js → records-NJiYvekn.js} +2 -2
  68. package/dist/chunks/{records-Cgvxz-Vx.js.map → records-NJiYvekn.js.map} +1 -1
  69. package/dist/chunks/{report-CgdsL9Hb.js → report-CwMfYa9J.js} +23 -23
  70. package/dist/chunks/{report-CgdsL9Hb.js.map → report-CwMfYa9J.js.map} +1 -1
  71. package/dist/chunks/round-trip-Cy3_SHRZ.js +79 -0
  72. package/dist/chunks/round-trip-Cy3_SHRZ.js.map +1 -0
  73. package/dist/chunks/{sigv4-LkAzsLAu.js → sigv4-BXwVbza3.js} +5 -5
  74. package/dist/chunks/sigv4-BXwVbza3.js.map +1 -0
  75. package/dist/chunks/{styles-CaABMoO1.js → styles-CAVmBLgp.js} +1237 -138
  76. package/dist/chunks/styles-CAVmBLgp.js.map +1 -0
  77. package/dist/chunks/styles-CPczw1Jz.js +1928 -0
  78. package/dist/chunks/styles-CPczw1Jz.js.map +1 -0
  79. package/dist/chunks/styles-boK6Ln54.js +2847 -0
  80. package/dist/chunks/styles-boK6Ln54.js.map +1 -0
  81. package/dist/chunks/{styles-yed-Cs1nmrjn.js → styles-yed-XeFBQ6VS.js} +506 -175
  82. package/dist/chunks/styles-yed-XeFBQ6VS.js.map +1 -0
  83. package/dist/chunks/{text-BuKQVMz2.js → text-ystE2bYi.js} +2 -2
  84. package/dist/chunks/{text-BuKQVMz2.js.map → text-ystE2bYi.js.map} +1 -1
  85. package/dist/csv.js +7 -7
  86. package/dist/cx.js +2 -2
  87. package/dist/cx2.js +2 -2
  88. package/dist/cys.js +1 -1
  89. package/dist/dot.js +8 -4
  90. package/dist/dot.js.map +1 -1
  91. package/dist/gexf.js +42 -12
  92. package/dist/gexf.js.map +1 -1
  93. package/dist/gml.js +848 -194
  94. package/dist/gml.js.map +1 -1
  95. package/dist/graph-io.js +230 -193
  96. package/dist/graph-io.js.map +1 -1
  97. package/dist/graphml.js +3 -3
  98. package/dist/json.js +3 -2
  99. package/dist/neo4j.js +6 -6
  100. package/dist/obo.js +1 -1
  101. package/dist/pajek.js +1 -1
  102. package/dist/positions.js +45 -3
  103. package/dist/positions.js.map +1 -1
  104. package/dist/sources-cypher.js +141 -23
  105. package/dist/sources-cypher.js.map +1 -1
  106. package/dist/sources-ndex.js +2 -2
  107. package/dist/sources-rest.js +32 -6
  108. package/dist/sources-rest.js.map +1 -1
  109. package/dist/sources-sparql.d.ts +1 -0
  110. package/dist/sources-sparql.js +439 -0
  111. package/dist/sources-sparql.js.map +1 -0
  112. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  113. package/dist/src/formats/cx/importer.js +5 -1
  114. package/dist/src/formats/cx/importer.js.map +1 -1
  115. package/dist/src/formats/cx/styles.d.ts +24 -1
  116. package/dist/src/formats/cx/styles.d.ts.map +1 -1
  117. package/dist/src/formats/cx/styles.js +117 -11
  118. package/dist/src/formats/cx/styles.js.map +1 -1
  119. package/dist/src/formats/cx2/importer.d.ts.map +1 -1
  120. package/dist/src/formats/cx2/importer.js +1 -0
  121. package/dist/src/formats/cx2/importer.js.map +1 -1
  122. package/dist/src/formats/cx2/styles.d.ts.map +1 -1
  123. package/dist/src/formats/cx2/styles.js +3 -1
  124. package/dist/src/formats/cx2/styles.js.map +1 -1
  125. package/dist/src/formats/cys/importer.d.ts.map +1 -1
  126. package/dist/src/formats/cys/importer.js +1 -0
  127. package/dist/src/formats/cys/importer.js.map +1 -1
  128. package/dist/src/formats/cys/styles.d.ts +2 -0
  129. package/dist/src/formats/cys/styles.d.ts.map +1 -1
  130. package/dist/src/formats/cys/styles.js +15 -7
  131. package/dist/src/formats/cys/styles.js.map +1 -1
  132. package/dist/src/formats/dot/drawing.d.ts +98 -0
  133. package/dist/src/formats/dot/drawing.d.ts.map +1 -0
  134. package/dist/src/formats/dot/drawing.js +734 -0
  135. package/dist/src/formats/dot/drawing.js.map +1 -0
  136. package/dist/src/formats/dot/exporter.d.ts.map +1 -1
  137. package/dist/src/formats/dot/exporter.js +34 -2
  138. package/dist/src/formats/dot/exporter.js.map +1 -1
  139. package/dist/src/formats/dot/importer.d.ts +6 -1
  140. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  141. package/dist/src/formats/dot/importer.js +170 -33
  142. package/dist/src/formats/dot/importer.js.map +1 -1
  143. package/dist/src/formats/dot/index.d.ts +3 -1
  144. package/dist/src/formats/dot/index.d.ts.map +1 -1
  145. package/dist/src/formats/dot/index.js +2 -1
  146. package/dist/src/formats/dot/index.js.map +1 -1
  147. package/dist/src/formats/dot/label-places.d.ts +41 -0
  148. package/dist/src/formats/dot/label-places.d.ts.map +1 -0
  149. package/dist/src/formats/dot/label-places.js +185 -0
  150. package/dist/src/formats/dot/label-places.js.map +1 -0
  151. package/dist/src/formats/dot/names.d.ts +13 -0
  152. package/dist/src/formats/dot/names.d.ts.map +1 -1
  153. package/dist/src/formats/dot/names.js +13 -0
  154. package/dist/src/formats/dot/names.js.map +1 -1
  155. package/dist/src/formats/dot/record.d.ts +50 -0
  156. package/dist/src/formats/dot/record.d.ts.map +1 -0
  157. package/dist/src/formats/dot/record.js +275 -0
  158. package/dist/src/formats/dot/record.js.map +1 -0
  159. package/dist/src/formats/dot/styles.d.ts +72 -2
  160. package/dist/src/formats/dot/styles.d.ts.map +1 -1
  161. package/dist/src/formats/dot/styles.js +1500 -119
  162. package/dist/src/formats/dot/styles.js.map +1 -1
  163. package/dist/src/formats/gexf/dialog-metrics.d.ts +15 -0
  164. package/dist/src/formats/gexf/dialog-metrics.d.ts.map +1 -0
  165. package/dist/src/formats/gexf/dialog-metrics.js +59 -0
  166. package/dist/src/formats/gexf/dialog-metrics.js.map +1 -0
  167. package/dist/src/formats/gexf/importer.d.ts +7 -0
  168. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  169. package/dist/src/formats/gexf/importer.js +41 -5
  170. package/dist/src/formats/gexf/importer.js.map +1 -1
  171. package/dist/src/formats/gexf/preview.d.ts +77 -0
  172. package/dist/src/formats/gexf/preview.d.ts.map +1 -0
  173. package/dist/src/formats/gexf/preview.js +191 -0
  174. package/dist/src/formats/gexf/preview.js.map +1 -0
  175. package/dist/src/formats/gexf/schema.d.ts.map +1 -1
  176. package/dist/src/formats/gexf/schema.js +2 -1
  177. package/dist/src/formats/gexf/schema.js.map +1 -1
  178. package/dist/src/formats/gexf/styles.d.ts +58 -31
  179. package/dist/src/formats/gexf/styles.d.ts.map +1 -1
  180. package/dist/src/formats/gexf/styles.js +848 -225
  181. package/dist/src/formats/gexf/styles.js.map +1 -1
  182. package/dist/src/formats/gml/importer.d.ts +5 -2
  183. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  184. package/dist/src/formats/gml/importer.js +258 -71
  185. package/dist/src/formats/gml/importer.js.map +1 -1
  186. package/dist/src/formats/gml/index.d.ts +1 -1
  187. package/dist/src/formats/gml/index.d.ts.map +1 -1
  188. package/dist/src/formats/gml/index.js +1 -1
  189. package/dist/src/formats/gml/index.js.map +1 -1
  190. package/dist/src/formats/gml/positions.d.ts +7 -0
  191. package/dist/src/formats/gml/positions.d.ts.map +1 -1
  192. package/dist/src/formats/gml/positions.js +29 -7
  193. package/dist/src/formats/gml/positions.js.map +1 -1
  194. package/dist/src/formats/gml/styles.d.ts.map +1 -1
  195. package/dist/src/formats/gml/styles.js +754 -102
  196. package/dist/src/formats/gml/styles.js.map +1 -1
  197. package/dist/src/formats/graphml/styles-plain.d.ts.map +1 -1
  198. package/dist/src/formats/graphml/styles-plain.js +6 -10
  199. package/dist/src/formats/graphml/styles-plain.js.map +1 -1
  200. package/dist/src/formats/graphml/styles-yed.d.ts +21 -15
  201. package/dist/src/formats/graphml/styles-yed.d.ts.map +1 -1
  202. package/dist/src/formats/graphml/styles-yed.js +695 -164
  203. package/dist/src/formats/graphml/styles-yed.js.map +1 -1
  204. package/dist/src/formats/graphml/styles-yfiles3.d.ts +1 -1
  205. package/dist/src/formats/graphml/styles-yfiles3.d.ts.map +1 -1
  206. package/dist/src/formats/graphml/styles-yfiles3.js +431 -64
  207. package/dist/src/formats/graphml/styles-yfiles3.js.map +1 -1
  208. package/dist/src/formats/graphml/yfiles.d.ts +3 -3
  209. package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
  210. package/dist/src/formats/graphml/yfiles.js +16 -6
  211. package/dist/src/formats/graphml/yfiles.js.map +1 -1
  212. package/dist/src/formats/json/dialect.d.ts +3 -2
  213. package/dist/src/formats/json/dialect.d.ts.map +1 -1
  214. package/dist/src/formats/json/dialect.js +39 -5
  215. package/dist/src/formats/json/dialect.js.map +1 -1
  216. package/dist/src/formats/json/importer.d.ts +13 -2
  217. package/dist/src/formats/json/importer.d.ts.map +1 -1
  218. package/dist/src/formats/json/importer.js +42 -6
  219. package/dist/src/formats/json/importer.js.map +1 -1
  220. package/dist/src/formats/json/index.d.ts +1 -1
  221. package/dist/src/formats/json/index.d.ts.map +1 -1
  222. package/dist/src/formats/json/index.js +1 -1
  223. package/dist/src/formats/json/index.js.map +1 -1
  224. package/dist/src/formats/json/positions.d.ts +5 -2
  225. package/dist/src/formats/json/positions.d.ts.map +1 -1
  226. package/dist/src/formats/json/positions.js +20 -4
  227. package/dist/src/formats/json/positions.js.map +1 -1
  228. package/dist/src/formats/json/styles.d.ts +12 -1
  229. package/dist/src/formats/json/styles.d.ts.map +1 -1
  230. package/dist/src/formats/json/styles.js +1843 -136
  231. package/dist/src/formats/json/styles.js.map +1 -1
  232. package/dist/src/formats/pajek/draw.d.ts +104 -0
  233. package/dist/src/formats/pajek/draw.d.ts.map +1 -0
  234. package/dist/src/formats/pajek/draw.js +382 -0
  235. package/dist/src/formats/pajek/draw.js.map +1 -0
  236. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  237. package/dist/src/formats/pajek/exporter.js +70 -51
  238. package/dist/src/formats/pajek/exporter.js.map +1 -1
  239. package/dist/src/formats/pajek/importer.d.ts +9 -0
  240. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  241. package/dist/src/formats/pajek/importer.js +233 -102
  242. package/dist/src/formats/pajek/importer.js.map +1 -1
  243. package/dist/src/formats/pajek/index.d.ts +1 -0
  244. package/dist/src/formats/pajek/index.d.ts.map +1 -1
  245. package/dist/src/formats/pajek/index.js.map +1 -1
  246. package/dist/src/formats/pajek/styles.d.ts +15 -7
  247. package/dist/src/formats/pajek/styles.d.ts.map +1 -1
  248. package/dist/src/formats/pajek/styles.js +1395 -114
  249. package/dist/src/formats/pajek/styles.js.map +1 -1
  250. package/dist/src/formats/pajek/syntax.d.ts +10 -1
  251. package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
  252. package/dist/src/formats/pajek/syntax.js +26 -2
  253. package/dist/src/formats/pajek/syntax.js.map +1 -1
  254. package/dist/src/formats/xgmml/emit.d.ts +1 -0
  255. package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
  256. package/dist/src/formats/xgmml/emit.js +65 -5
  257. package/dist/src/formats/xgmml/emit.js.map +1 -1
  258. package/dist/src/formats/xgmml/styles.d.ts +23 -3
  259. package/dist/src/formats/xgmml/styles.d.ts.map +1 -1
  260. package/dist/src/formats/xgmml/styles.js +277 -60
  261. package/dist/src/formats/xgmml/styles.js.map +1 -1
  262. package/dist/src/index.d.ts +6 -5
  263. package/dist/src/index.d.ts.map +1 -1
  264. package/dist/src/index.js +6 -5
  265. package/dist/src/index.js.map +1 -1
  266. package/dist/src/positions/convert.d.ts.map +1 -1
  267. package/dist/src/positions/convert.js +11 -1
  268. package/dist/src/positions/convert.js.map +1 -1
  269. package/dist/src/positions/extract.d.ts.map +1 -1
  270. package/dist/src/positions/extract.js +53 -1
  271. package/dist/src/positions/extract.js.map +1 -1
  272. package/dist/src/positions/index.d.ts +1 -1
  273. package/dist/src/positions/index.d.ts.map +1 -1
  274. package/dist/src/positions/types.d.ts +59 -0
  275. package/dist/src/positions/types.d.ts.map +1 -1
  276. package/dist/src/sources/builtins.d.ts +1 -1
  277. package/dist/src/sources/builtins.d.ts.map +1 -1
  278. package/dist/src/sources/builtins.js +8 -2
  279. package/dist/src/sources/builtins.js.map +1 -1
  280. package/dist/src/sources/context.d.ts.map +1 -1
  281. package/dist/src/sources/context.js +1 -0
  282. package/dist/src/sources/context.js.map +1 -1
  283. package/dist/src/sources/credentials.d.ts +50 -1
  284. package/dist/src/sources/credentials.d.ts.map +1 -1
  285. package/dist/src/sources/credentials.js +69 -0
  286. package/dist/src/sources/credentials.js.map +1 -1
  287. package/dist/src/sources/cypher/descriptor.d.ts.map +1 -1
  288. package/dist/src/sources/cypher/descriptor.js +5 -0
  289. package/dist/src/sources/cypher/descriptor.js.map +1 -1
  290. package/dist/src/sources/cypher/index.d.ts.map +1 -1
  291. package/dist/src/sources/cypher/index.js +125 -18
  292. package/dist/src/sources/cypher/index.js.map +1 -1
  293. package/dist/src/sources/cypher/params.d.ts +1 -1
  294. package/dist/src/sources/cypher/params.d.ts.map +1 -1
  295. package/dist/src/sources/cypher/query-builder.d.ts +17 -0
  296. package/dist/src/sources/cypher/query-builder.d.ts.map +1 -1
  297. package/dist/src/sources/cypher/query-builder.js +31 -0
  298. package/dist/src/sources/cypher/query-builder.js.map +1 -1
  299. package/dist/src/sources/ids.d.ts +5 -0
  300. package/dist/src/sources/ids.d.ts.map +1 -1
  301. package/dist/src/sources/ids.js +5 -0
  302. package/dist/src/sources/ids.js.map +1 -1
  303. package/dist/src/sources/params.d.ts +3 -0
  304. package/dist/src/sources/params.d.ts.map +1 -1
  305. package/dist/src/sources/rest/descriptor.d.ts.map +1 -1
  306. package/dist/src/sources/rest/descriptor.js +9 -0
  307. package/dist/src/sources/rest/descriptor.js.map +1 -1
  308. package/dist/src/sources/rest/openalex.d.ts +4 -2
  309. package/dist/src/sources/rest/openalex.d.ts.map +1 -1
  310. package/dist/src/sources/rest/openalex.js +4 -2
  311. package/dist/src/sources/rest/openalex.js.map +1 -1
  312. package/dist/src/sources/rest/source.d.ts.map +1 -1
  313. package/dist/src/sources/rest/source.js +38 -0
  314. package/dist/src/sources/rest/source.js.map +1 -1
  315. package/dist/src/sources/run.d.ts +2 -0
  316. package/dist/src/sources/run.d.ts.map +1 -1
  317. package/dist/src/sources/run.js +30 -3
  318. package/dist/src/sources/run.js.map +1 -1
  319. package/dist/src/sources/sigv4.d.ts +5 -3
  320. package/dist/src/sources/sigv4.d.ts.map +1 -1
  321. package/dist/src/sources/sigv4.js +6 -4
  322. package/dist/src/sources/sigv4.js.map +1 -1
  323. package/dist/src/sources/sparql/descriptor.d.ts +10 -0
  324. package/dist/src/sources/sparql/descriptor.d.ts.map +1 -0
  325. package/dist/src/sources/sparql/descriptor.js +64 -0
  326. package/dist/src/sources/sparql/descriptor.js.map +1 -0
  327. package/dist/src/sources/sparql/index.d.ts +28 -0
  328. package/dist/src/sources/sparql/index.d.ts.map +1 -0
  329. package/dist/src/sources/sparql/index.js +327 -0
  330. package/dist/src/sources/sparql/index.js.map +1 -0
  331. package/dist/src/sources/sparql/ntriples.d.ts +69 -0
  332. package/dist/src/sources/sparql/ntriples.d.ts.map +1 -0
  333. package/dist/src/sources/sparql/ntriples.js +180 -0
  334. package/dist/src/sources/sparql/ntriples.js.map +1 -0
  335. package/dist/src/sources/sparql/params.d.ts +27 -0
  336. package/dist/src/sources/sparql/params.d.ts.map +1 -0
  337. package/dist/src/sources/sparql/params.js +5 -0
  338. package/dist/src/sources/sparql/params.js.map +1 -0
  339. package/dist/src/sources/sparql/query.d.ts +73 -0
  340. package/dist/src/sources/sparql/query.d.ts.map +1 -0
  341. package/dist/src/sources/sparql/query.js +164 -0
  342. package/dist/src/sources/sparql/query.js.map +1 -0
  343. package/dist/src/sources/types.d.ts +60 -0
  344. package/dist/src/sources/types.d.ts.map +1 -1
  345. package/dist/src/styles/annotations.d.ts +61 -5
  346. package/dist/src/styles/annotations.d.ts.map +1 -1
  347. package/dist/src/styles/annotations.js +130 -22
  348. package/dist/src/styles/annotations.js.map +1 -1
  349. package/dist/src/styles/canon/bends.d.ts +46 -0
  350. package/dist/src/styles/canon/bends.d.ts.map +1 -1
  351. package/dist/src/styles/canon/bends.js +123 -0
  352. package/dist/src/styles/canon/bends.js.map +1 -1
  353. package/dist/src/styles/canon/color-tables.d.ts +6 -1
  354. package/dist/src/styles/canon/color-tables.d.ts.map +1 -1
  355. package/dist/src/styles/canon/color-tables.js +10 -4
  356. package/dist/src/styles/canon/color-tables.js.map +1 -1
  357. package/dist/src/styles/canon/color.d.ts +3 -1
  358. package/dist/src/styles/canon/color.d.ts.map +1 -1
  359. package/dist/src/styles/canon/color.js +103 -3
  360. package/dist/src/styles/canon/color.js.map +1 -1
  361. package/dist/src/styles/canon/enums.d.ts +2 -2
  362. package/dist/src/styles/canon/enums.d.ts.map +1 -1
  363. package/dist/src/styles/canon/enums.js +89 -7
  364. package/dist/src/styles/canon/enums.js.map +1 -1
  365. package/dist/src/styles/canon/graphviz.d.ts +12 -3
  366. package/dist/src/styles/canon/graphviz.d.ts.map +1 -1
  367. package/dist/src/styles/canon/graphviz.js +57 -9
  368. package/dist/src/styles/canon/graphviz.js.map +1 -1
  369. package/dist/src/styles/canon/number.d.ts +8 -0
  370. package/dist/src/styles/canon/number.d.ts.map +1 -1
  371. package/dist/src/styles/canon/number.js +18 -0
  372. package/dist/src/styles/canon/number.js.map +1 -1
  373. package/dist/src/styles/canon/text.d.ts +29 -2
  374. package/dist/src/styles/canon/text.d.ts.map +1 -1
  375. package/dist/src/styles/canon/text.js +156 -16
  376. package/dist/src/styles/canon/text.js.map +1 -1
  377. package/dist/src/styles/codes.d.ts +2 -0
  378. package/dist/src/styles/codes.d.ts.map +1 -1
  379. package/dist/src/styles/codes.js +2 -0
  380. package/dist/src/styles/codes.js.map +1 -1
  381. package/dist/src/styles/cyjs/cascade.d.ts.map +1 -1
  382. package/dist/src/styles/cyjs/cascade.js +1139 -79
  383. package/dist/src/styles/cyjs/cascade.js.map +1 -1
  384. package/dist/src/styles/cyjs/defaults-table.d.ts.map +1 -1
  385. package/dist/src/styles/cyjs/defaults-table.js +4 -0
  386. package/dist/src/styles/cyjs/defaults-table.js.map +1 -1
  387. package/dist/src/styles/cyjs/emit.d.ts.map +1 -1
  388. package/dist/src/styles/cyjs/emit.js +232 -10
  389. package/dist/src/styles/cyjs/emit.js.map +1 -1
  390. package/dist/src/styles/cyjs/face.d.ts +20 -0
  391. package/dist/src/styles/cyjs/face.d.ts.map +1 -0
  392. package/dist/src/styles/cyjs/face.js +332 -0
  393. package/dist/src/styles/cyjs/face.js.map +1 -0
  394. package/dist/src/styles/cyjs/mappers.d.ts +44 -1
  395. package/dist/src/styles/cyjs/mappers.d.ts.map +1 -1
  396. package/dist/src/styles/cyjs/mappers.js +475 -26
  397. package/dist/src/styles/cyjs/mappers.js.map +1 -1
  398. package/dist/src/styles/cyjs/routes.d.ts +53 -0
  399. package/dist/src/styles/cyjs/routes.d.ts.map +1 -0
  400. package/dist/src/styles/cyjs/routes.js +360 -0
  401. package/dist/src/styles/cyjs/routes.js.map +1 -0
  402. package/dist/src/styles/cytoscape/charts.d.ts +23 -0
  403. package/dist/src/styles/cytoscape/charts.d.ts.map +1 -0
  404. package/dist/src/styles/cytoscape/charts.js +560 -0
  405. package/dist/src/styles/cytoscape/charts.js.map +1 -0
  406. package/dist/src/styles/cytoscape/emit.d.ts.map +1 -1
  407. package/dist/src/styles/cytoscape/emit.js +156 -48
  408. package/dist/src/styles/cytoscape/emit.js.map +1 -1
  409. package/dist/src/styles/cytoscape/lexicon.d.ts +91 -3
  410. package/dist/src/styles/cytoscape/lexicon.d.ts.map +1 -1
  411. package/dist/src/styles/cytoscape/lexicon.js +387 -77
  412. package/dist/src/styles/cytoscape/lexicon.js.map +1 -1
  413. package/dist/src/styles/cytoscape/mappings.d.ts +30 -0
  414. package/dist/src/styles/cytoscape/mappings.d.ts.map +1 -1
  415. package/dist/src/styles/cytoscape/mappings.js +92 -0
  416. package/dist/src/styles/cytoscape/mappings.js.map +1 -1
  417. package/dist/src/styles/cytoscape/resolve.d.ts +42 -2
  418. package/dist/src/styles/cytoscape/resolve.d.ts.map +1 -1
  419. package/dist/src/styles/cytoscape/resolve.js +623 -17
  420. package/dist/src/styles/cytoscape/resolve.js.map +1 -1
  421. package/dist/src/styles/defaults.d.ts +46 -26
  422. package/dist/src/styles/defaults.d.ts.map +1 -1
  423. package/dist/src/styles/defaults.js +308 -71
  424. package/dist/src/styles/defaults.js.map +1 -1
  425. package/dist/src/styles/index.d.ts +4 -3
  426. package/dist/src/styles/index.d.ts.map +1 -1
  427. package/dist/src/styles/index.js +3 -2
  428. package/dist/src/styles/index.js.map +1 -1
  429. package/dist/src/styles/internal.d.ts +1 -0
  430. package/dist/src/styles/internal.d.ts.map +1 -1
  431. package/dist/src/styles/internal.js +1 -0
  432. package/dist/src/styles/internal.js.map +1 -1
  433. package/dist/src/styles/io/generic.d.ts.map +1 -1
  434. package/dist/src/styles/io/generic.js +56 -16
  435. package/dist/src/styles/io/generic.js.map +1 -1
  436. package/dist/src/styles/io/round-trip.d.ts +56 -0
  437. package/dist/src/styles/io/round-trip.d.ts.map +1 -0
  438. package/dist/src/styles/io/round-trip.js +138 -0
  439. package/dist/src/styles/io/round-trip.js.map +1 -0
  440. package/dist/src/styles/io/writer.d.ts.map +1 -1
  441. package/dist/src/styles/io/writer.js +6 -1
  442. package/dist/src/styles/io/writer.js.map +1 -1
  443. package/dist/src/styles/notes.d.ts.map +1 -1
  444. package/dist/src/styles/notes.js +1 -0
  445. package/dist/src/styles/notes.js.map +1 -1
  446. package/dist/src/styles/plan/features.d.ts +1 -1
  447. package/dist/src/styles/plan/features.d.ts.map +1 -1
  448. package/dist/src/styles/plan/features.js +22 -2
  449. package/dist/src/styles/plan/features.js.map +1 -1
  450. package/dist/src/styles/plan/index.d.ts +1 -1
  451. package/dist/src/styles/plan/index.d.ts.map +1 -1
  452. package/dist/src/styles/plan/index.js +1 -1
  453. package/dist/src/styles/plan/index.js.map +1 -1
  454. package/dist/src/styles/plan/plan.d.ts.map +1 -1
  455. package/dist/src/styles/plan/plan.js +61 -4
  456. package/dist/src/styles/plan/plan.js.map +1 -1
  457. package/dist/src/styles/plan/resolve.d.ts +11 -0
  458. package/dist/src/styles/plan/resolve.d.ts.map +1 -1
  459. package/dist/src/styles/plan/resolve.js +40 -4
  460. package/dist/src/styles/plan/resolve.js.map +1 -1
  461. package/dist/src/styles/slots.d.ts +14 -0
  462. package/dist/src/styles/slots.d.ts.map +1 -0
  463. package/dist/src/styles/slots.js +20 -0
  464. package/dist/src/styles/slots.js.map +1 -0
  465. package/dist/src/styles/types.d.ts +687 -6
  466. package/dist/src/styles/types.d.ts.map +1 -1
  467. package/dist/src/styles/vocabulary.d.ts +3 -2
  468. package/dist/src/styles/vocabulary.d.ts.map +1 -1
  469. package/dist/src/styles/vocabulary.js +224 -0
  470. package/dist/src/styles/vocabulary.js.map +1 -1
  471. package/dist/styles.js +30 -239
  472. package/dist/styles.js.map +1 -1
  473. package/dist/xgmml.js +3 -3
  474. package/package.json +27 -7
  475. package/src/formats/cx/importer.ts +6 -1
  476. package/src/formats/cx/styles.ts +143 -9
  477. package/src/formats/cx2/importer.ts +1 -0
  478. package/src/formats/cx2/styles.ts +3 -1
  479. package/src/formats/cys/importer.ts +1 -0
  480. package/src/formats/cys/styles.ts +27 -5
  481. package/src/formats/dot/drawing.ts +799 -0
  482. package/src/formats/dot/exporter.ts +37 -1
  483. package/src/formats/dot/importer.ts +192 -36
  484. package/src/formats/dot/index.ts +3 -1
  485. package/src/formats/dot/label-places.ts +241 -0
  486. package/src/formats/dot/names.ts +15 -0
  487. package/src/formats/dot/record.ts +336 -0
  488. package/src/formats/dot/styles.ts +1702 -149
  489. package/src/formats/gexf/dialog-metrics.ts +61 -0
  490. package/src/formats/gexf/importer.ts +50 -5
  491. package/src/formats/gexf/preview.ts +217 -0
  492. package/src/formats/gexf/schema.ts +2 -1
  493. package/src/formats/gexf/styles.ts +1099 -245
  494. package/src/formats/gml/importer.ts +291 -76
  495. package/src/formats/gml/index.ts +1 -1
  496. package/src/formats/gml/positions.ts +29 -7
  497. package/src/formats/gml/styles.ts +852 -110
  498. package/src/formats/graphml/styles-plain.ts +6 -15
  499. package/src/formats/graphml/styles-yed.ts +765 -176
  500. package/src/formats/graphml/styles-yfiles3.ts +487 -63
  501. package/src/formats/graphml/yfiles.ts +19 -6
  502. package/src/formats/json/dialect.ts +41 -5
  503. package/src/formats/json/importer.ts +59 -7
  504. package/src/formats/json/index.ts +1 -0
  505. package/src/formats/json/positions.ts +22 -5
  506. package/src/formats/json/styles.ts +2123 -171
  507. package/src/formats/pajek/draw.ts +469 -0
  508. package/src/formats/pajek/exporter.ts +81 -49
  509. package/src/formats/pajek/importer.ts +278 -103
  510. package/src/formats/pajek/index.ts +1 -0
  511. package/src/formats/pajek/styles.ts +1506 -133
  512. package/src/formats/pajek/syntax.ts +27 -2
  513. package/src/formats/xgmml/emit.ts +73 -5
  514. package/src/formats/xgmml/styles.ts +330 -71
  515. package/src/index.ts +12 -1
  516. package/src/positions/convert.ts +12 -1
  517. package/src/positions/extract.ts +55 -1
  518. package/src/positions/index.ts +1 -0
  519. package/src/positions/types.ts +60 -0
  520. package/src/sources/builtins.ts +8 -1
  521. package/src/sources/context.ts +1 -0
  522. package/src/sources/credentials.ts +90 -1
  523. package/src/sources/cypher/descriptor.ts +7 -1
  524. package/src/sources/cypher/index.ts +149 -18
  525. package/src/sources/cypher/params.ts +1 -1
  526. package/src/sources/cypher/query-builder.ts +33 -0
  527. package/src/sources/ids.ts +6 -0
  528. package/src/sources/params.ts +3 -0
  529. package/src/sources/rest/descriptor.ts +9 -0
  530. package/src/sources/rest/openalex.ts +4 -2
  531. package/src/sources/rest/source.ts +41 -0
  532. package/src/sources/run.ts +35 -3
  533. package/src/sources/sigv4.ts +6 -4
  534. package/src/sources/sparql/descriptor.ts +67 -0
  535. package/src/sources/sparql/index.ts +371 -0
  536. package/src/sources/sparql/ntriples.ts +219 -0
  537. package/src/sources/sparql/params.ts +28 -0
  538. package/src/sources/sparql/query.ts +216 -0
  539. package/src/sources/types.ts +68 -0
  540. package/src/styles/annotations.ts +201 -27
  541. package/src/styles/canon/bends.ts +137 -0
  542. package/src/styles/canon/color-tables.ts +10 -4
  543. package/src/styles/canon/color.ts +105 -3
  544. package/src/styles/canon/enums.ts +107 -8
  545. package/src/styles/canon/graphviz.ts +71 -10
  546. package/src/styles/canon/number.ts +19 -0
  547. package/src/styles/canon/text.ts +187 -16
  548. package/src/styles/codes.ts +2 -0
  549. package/src/styles/cyjs/cascade.ts +1303 -84
  550. package/src/styles/cyjs/defaults-table.ts +4 -0
  551. package/src/styles/cyjs/emit.ts +268 -14
  552. package/src/styles/cyjs/face.ts +372 -0
  553. package/src/styles/cyjs/mappers.ts +506 -27
  554. package/src/styles/cyjs/routes.ts +432 -0
  555. package/src/styles/cytoscape/charts.ts +684 -0
  556. package/src/styles/cytoscape/emit.ts +170 -48
  557. package/src/styles/cytoscape/lexicon.ts +431 -78
  558. package/src/styles/cytoscape/mappings.ts +108 -0
  559. package/src/styles/cytoscape/resolve.ts +741 -17
  560. package/src/styles/defaults.ts +417 -108
  561. package/src/styles/index.ts +5 -0
  562. package/src/styles/internal.ts +1 -0
  563. package/src/styles/io/generic.ts +79 -23
  564. package/src/styles/io/round-trip.ts +202 -0
  565. package/src/styles/io/writer.ts +6 -1
  566. package/src/styles/notes.ts +1 -0
  567. package/src/styles/plan/features.ts +23 -2
  568. package/src/styles/plan/index.ts +1 -1
  569. package/src/styles/plan/plan.ts +69 -5
  570. package/src/styles/plan/resolve.ts +47 -4
  571. package/src/styles/slots.ts +25 -0
  572. package/src/styles/types.ts +698 -5
  573. package/src/styles/vocabulary.ts +232 -2
  574. package/dist/chunks/block-Cu22ewuS.js.map +0 -1
  575. package/dist/chunks/choose-Cdx6Enl2.js +0 -57
  576. package/dist/chunks/choose-Cdx6Enl2.js.map +0 -1
  577. package/dist/chunks/codes-CV_Bhcyi.js.map +0 -1
  578. package/dist/chunks/convert-BcQ8_jMo.js.map +0 -1
  579. package/dist/chunks/credentials-BiQsnMTb.js.map +0 -1
  580. package/dist/chunks/descriptor-BJ-W0Jd-.js.map +0 -1
  581. package/dist/chunks/emit-CD8xnY8s.js.map +0 -1
  582. package/dist/chunks/export-CZ7VRm4I.js.map +0 -1
  583. package/dist/chunks/exporter-bxxjOrDZ.js.map +0 -1
  584. package/dist/chunks/format-BMS-1Nxb.js +0 -64
  585. package/dist/chunks/format-BMS-1Nxb.js.map +0 -1
  586. package/dist/chunks/generic-CP6YD34u.js.map +0 -1
  587. package/dist/chunks/importer-B87_fmVx.js.map +0 -1
  588. package/dist/chunks/importer-CB_zV5_L.js.map +0 -1
  589. package/dist/chunks/importer-CVT-JyDE.js.map +0 -1
  590. package/dist/chunks/importer-Cyy6UseH.js.map +0 -1
  591. package/dist/chunks/importer-DPZDN40-.js.map +0 -1
  592. package/dist/chunks/importer-e3huMZbm.js.map +0 -1
  593. package/dist/chunks/lexicon-u2SI5xcx.js.map +0 -1
  594. package/dist/chunks/sigv4-LkAzsLAu.js.map +0 -1
  595. package/dist/chunks/styles-CaABMoO1.js.map +0 -1
  596. package/dist/chunks/styles-P_gmFAOi.js +0 -770
  597. package/dist/chunks/styles-P_gmFAOi.js.map +0 -1
  598. package/dist/chunks/styles-yed-Cs1nmrjn.js.map +0 -1
  599. package/dist/chunks/writer-DvHTl36J.js +0 -449
  600. package/dist/chunks/writer-DvHTl36J.js.map +0 -1
@@ -0,0 +1,216 @@
1
+ /**
2
+ * The SPARQL the source sends: the caller's CONSTRUCT or DESCRIBE with the paging the source
3
+ * adds (`ORDER BY` the template's variables, `LIMIT` and `OFFSET`), and the generated queries of
4
+ * "all", "neighborhood" and expand (`VALUES ?s { ... }`).
5
+ */
6
+
7
+ /** Characters an IRIREF may not hold. */
8
+ const NOT_IRI = /[\s<>"{}|^`\\]/;
9
+
10
+ /** A language tag a filter may name. */
11
+ const LANGUAGE = /^[a-z]{1,8}(-[a-z\d]{1,8})*$/i;
12
+
13
+ /** The query forms, as the first keyword after the prologue. */
14
+ type QueryForm = "construct" | "describe" | "select" | "ask" | null;
15
+
16
+ /** What paging the caller's query takes. */
17
+ interface UserQuery {
18
+ /** Its form. */
19
+ readonly form: QueryForm;
20
+ /** Whether it sets its own LIMIT or OFFSET, so the source sends it as written. */
21
+ readonly ownLimit: boolean;
22
+ /** Whether it orders its solutions itself. */
23
+ readonly ordered: boolean;
24
+ /** The variables of a CONSTRUCT template, in order, for ORDER BY. */
25
+ readonly templateVars: readonly string[];
26
+ }
27
+
28
+ /**
29
+ * The query with IRIs, strings and comments blanked out, so keywords and braces can be found.
30
+ * @param query - the query
31
+ * @returns the bare text
32
+ */
33
+ function bare(query: string): string {
34
+ return query
35
+ .replaceAll(/<[^<>\s]*>/g, "<>")
36
+ .replaceAll(/"""[\s\S]*?"""|'''[\s\S]*?'''|"(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*'/g, '""')
37
+ .replaceAll(/#[^\n]*/g, "");
38
+ }
39
+
40
+ /** The keywords of SPARQL Update, which a query this source sends never holds. */
41
+ const UPDATE_KEYWORDS = /\b(INSERT|DELETE|LOAD|CLEAR|DROP|CREATE|ADD|MOVE|COPY|WITH)\b/i;
42
+
43
+ /** One declaration of the prologue, as `bare` leaves it: `BASE <>` or `PREFIX ex: <>`. */
44
+ const DECLARATION = /^\s*(?:BASE|PREFIX\s*[^\s:<]*:)\s*<>/i;
45
+
46
+ /**
47
+ * Bare text after its prologue, one declaration at a time.
48
+ * @param text - the bare text
49
+ * @returns what follows the prologue
50
+ */
51
+ function afterPrologue(text: string): string {
52
+ let rest = text;
53
+ for (let found = DECLARATION.exec(rest); found !== null; found = DECLARATION.exec(rest)) {
54
+ rest = rest.slice(found[0].length);
55
+ }
56
+ return rest;
57
+ }
58
+
59
+ /**
60
+ * The bare text with variables and prefixed names blanked too, so a name such as `ex:LIMIT` or
61
+ * `?DELETE` is never read as a keyword.
62
+ * @param text - the bare text after the prologue
63
+ * @returns the text holding only keywords, punctuation and blanks
64
+ */
65
+ function keywordsOnly(text: string): string {
66
+ // one run of name characters at a time: a run holding a colon is a prefixed name
67
+ return text.replaceAll(/[?$]\w+/g, "?v").replaceAll(/[\w.%:-]+/g, (run) => (run.includes(":") ? "_" : run));
68
+ }
69
+
70
+ /**
71
+ * Whether bare text holds a `;` outside every brace: SPARQL Update separates its operations so, and
72
+ * a query never holds one there.
73
+ * @param text - the text
74
+ * @returns true when it does
75
+ */
76
+ function semicolonOutside(text: string): boolean {
77
+ let depth = 0;
78
+ for (const char of text) {
79
+ if (char === "{") {
80
+ depth++;
81
+ } else if (char === "}") {
82
+ depth--;
83
+ } else if (char === ";" && depth <= 0) {
84
+ return true;
85
+ }
86
+ }
87
+ return false;
88
+ }
89
+
90
+ /**
91
+ * Read what paging a caller's query takes. Its form is the first keyword after the prologue; a
92
+ * text that holds an update keyword, or a `;` outside braces, has no form, so it is refused.
93
+ * @param query - the query
94
+ * @returns its form, its own modifiers and its template variables
95
+ */
96
+ export function readQuery(query: string): UserQuery {
97
+ const body = afterPrologue(bare(query));
98
+ const text = keywordsOnly(body);
99
+ const first = /^\s*([A-Za-z]+)/.exec(text)?.[1]?.toUpperCase() ?? "";
100
+ const update = UPDATE_KEYWORDS.test(text) || semicolonOutside(text);
101
+ const form = !update && ["CONSTRUCT", "DESCRIBE", "SELECT", "ASK"].includes(first) ? first.toLowerCase() : null;
102
+ // the solution modifiers follow the last closing brace (a trailing VALUES block is not handled)
103
+ const tail = text.slice(text.lastIndexOf("}") + 1);
104
+ let templateVars: string[] = [];
105
+ if (form === "construct") {
106
+ const template = /\bCONSTRUCT\s*\{([^}]*)\}/i.exec(body)?.[1] ?? "";
107
+ templateVars = [...new Set(template.match(/[?$]\w+/g) ?? [])].map((v) => `?${v.slice(1)}`);
108
+ }
109
+ return {
110
+ form: form as QueryForm,
111
+ ownLimit: /\b(LIMIT|OFFSET)\b/i.test(tail),
112
+ ordered: /\bORDER\s+BY\b/i.test(tail),
113
+ templateVars,
114
+ };
115
+ }
116
+
117
+ /**
118
+ * The caller's query with one page's modifiers added.
119
+ * @param query - the query
120
+ * @param shape - what readQuery found
121
+ * @param limit - solutions per page
122
+ * @param offset - solutions to skip
123
+ * @returns the query to send
124
+ */
125
+ export function pagedQuery(query: string, shape: UserQuery, limit: number, offset: number): string {
126
+ const order = shape.ordered || shape.templateVars.length === 0 ? "" : `\nORDER BY ${shape.templateVars.join(" ")}`;
127
+ const skip = offset > 0 ? ` OFFSET ${String(offset)}` : "";
128
+ return `${query.trimEnd()}${order}\nLIMIT ${String(limit)}${skip}`;
129
+ }
130
+
131
+ /**
132
+ * An IRI as a SPARQL term, or null when it cannot be one.
133
+ * @param id - the id
134
+ * @returns `<iri>`, or null
135
+ */
136
+ export function iriTerm(id: unknown): string | null {
137
+ const text = String(id);
138
+ return /^[a-z][\w+.-]*:/i.test(text) && !NOT_IRI.test(text) ? `<${text}>` : null;
139
+ }
140
+
141
+ /** What generated queries keep: literals in a language, edges along some predicates. */
142
+ interface TripleFilter {
143
+ /** Keep literals tagged with this language or untagged; "" keeps every literal. */
144
+ readonly language: string;
145
+ /** Keep edges whose predicate starts with one of these IRIs; empty keeps every edge. */
146
+ readonly predicates: readonly string[];
147
+ }
148
+
149
+ /**
150
+ * The FILTERs of generated queries, or "" for none. Both values are checked by the caller.
151
+ * @param filter - the language and the predicate prefixes
152
+ * @returns the FILTER clauses
153
+ */
154
+ function filters(filter: TripleFilter): string {
155
+ const { language, predicates } = filter;
156
+ const lang =
157
+ language === "" ? "" : ` FILTER(!isLiteral(?o) || lang(?o) = "" || langMatches(lang(?o), "${language}"))`;
158
+ const along = predicates.map((p) => `STRSTARTS(STR(?p), "${p}")`).join(" || ");
159
+ return predicates.length === 0 ? lang : `${lang} FILTER(isLiteral(?o) || ${along})`;
160
+ }
161
+
162
+ /**
163
+ * Whether a language tag may go into a FILTER.
164
+ * @param language - the tag
165
+ * @returns whether it is well formed
166
+ */
167
+ export function validLanguage(language: string): boolean {
168
+ return LANGUAGE.test(language);
169
+ }
170
+
171
+ /**
172
+ * Mode "all": every triple, ordered so pages are stable.
173
+ * @param filter - what to keep
174
+ * @param limit - solutions per page
175
+ * @param offset - solutions to skip
176
+ * @returns the query
177
+ */
178
+ export function allQuery(filter: TripleFilter, limit: number, offset: number): string {
179
+ return pagedQuery(
180
+ `CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o .${filters(filter)} }`,
181
+ { form: "construct", ownLimit: false, ordered: false, templateVars: ["?s", "?p", "?o"] },
182
+ limit,
183
+ offset,
184
+ );
185
+ }
186
+
187
+ /**
188
+ * The triples around some IRIs: out (`VALUES ?s`), in (`VALUES ?o`) or both.
189
+ * @param iris - the IRIs as terms
190
+ * @param direction - which triples
191
+ * @param filter - what to keep
192
+ * @param limit - solutions per page
193
+ * @param offset - solutions to skip
194
+ * @returns the query
195
+ */
196
+ export function aroundQuery(
197
+ iris: readonly string[],
198
+ direction: "out" | "in" | "both",
199
+ filter: TripleFilter,
200
+ limit: number,
201
+ offset: number,
202
+ ): string {
203
+ const values = iris.join(" ");
204
+ const out = `{ VALUES ?s { ${values} } ?s ?p ?o .${filters(filter)} }`;
205
+ const inward = `{ VALUES ?o { ${values} } ?s ?p ?o .${filters({ ...filter, language: "" })} }`;
206
+ let where = `${out} UNION ${inward}`;
207
+ if (direction !== "both") {
208
+ where = direction === "out" ? out : inward;
209
+ }
210
+ return pagedQuery(
211
+ `CONSTRUCT { ?s ?p ?o } WHERE { ${where} }`,
212
+ { form: "construct", ownLimit: false, ordered: false, templateVars: ["?s", "?p", "?o"] },
213
+ limit,
214
+ offset,
215
+ );
216
+ }
@@ -223,6 +223,18 @@ export interface RetryOptions {
223
223
  readonly maxDelayMs?: number | undefined;
224
224
  }
225
225
 
226
+ /**
227
+ * How much a source holds for a load, as it counted it, so a caller can show "100 of 28,455".
228
+ * Experimental.
229
+ * @category Network sources
230
+ */
231
+ export interface SourceTotal {
232
+ /** The nodes the load's params match at the source. */
233
+ readonly nodes?: number | undefined;
234
+ /** The edges the load's params match at the source. */
235
+ readonly edges?: number | undefined;
236
+ }
237
+
226
238
  /**
227
239
  * Facts a source reports with `ctx.finish()`. Experimental.
228
240
  * @category Network sources
@@ -243,6 +255,8 @@ export interface SourceFinish {
243
255
  | undefined;
244
256
  /** What lets a later call tell whether the data changed. */
245
257
  readonly validators?: SourceValidators | undefined;
258
+ /** What the source holds for this load, when it counted: the nodes and edges it matches. */
259
+ readonly total?: SourceTotal | undefined;
246
260
  }
247
261
 
248
262
  /**
@@ -357,6 +371,39 @@ export interface SourceSample {
357
371
  | undefined;
358
372
  /** false: too big to load whole; start from a neighborhood. */
359
373
  readonly whole?: boolean | undefined;
374
+ /**
375
+ * A node cap for loading the sample when the caller gives none, for a sample too big to load
376
+ * whole that pages: the load stops at the first page past it, and its cursor reads on.
377
+ */
378
+ readonly firstPage?: number | undefined;
379
+ }
380
+
381
+ /**
382
+ * One credential a source takes, as its descriptor declares it: a name a project file records
383
+ * instead of the credential, the kind, whether a load needs it, and for an API key how it is sent.
384
+ * `credentials.forSlot(slot, value)` makes the credential it describes. Experimental.
385
+ * @category Network sources
386
+ */
387
+ export interface SourceCredentialSlot {
388
+ /** The slot's name, recorded as a load's `credentialSlot` ("api_key", "default"). */
389
+ readonly name: string;
390
+ /** The credential kind it takes. */
391
+ readonly kind: CredentialKind;
392
+ /** Whether a load needs it. @defaultValue false */
393
+ readonly required?: boolean | undefined;
394
+ /** Its default name; catalog data an application may replace by name. */
395
+ readonly plainName?: string | undefined;
396
+ /** For an API key: the query parameter or request header it is sent in. */
397
+ readonly send?:
398
+ | {
399
+ /** The query parameter the key is sent in. */
400
+ readonly query: string;
401
+ }
402
+ | {
403
+ /** The request header the key is sent in. */
404
+ readonly header: string;
405
+ }
406
+ | undefined;
360
407
  }
361
408
 
362
409
  /**
@@ -377,6 +424,25 @@ export interface SourceDescriptor {
377
424
  readonly auth?: readonly CredentialKind[] | undefined;
378
425
  /** Whether a credential is needed. @defaultValue "none" */
379
426
  readonly authRequired?: "required" | "optional" | "none" | undefined;
427
+ /**
428
+ * The credential slots it takes. A source that takes a credential (`auth`) and declares none
429
+ * has one slot, `default`: `credentialSlots(descriptor)` reads either. @defaultValue []
430
+ */
431
+ readonly credentials?: readonly SourceCredentialSlot[] | undefined;
432
+ /**
433
+ * Where an `api-key` credential goes, for a form that asks for the key alone: pass it to
434
+ * `credentials.apiKey(descriptor.apiKey, key)`. Absent when the caller must say.
435
+ */
436
+ readonly apiKey?:
437
+ | {
438
+ /** The request header that carries the key. */
439
+ readonly header: string;
440
+ }
441
+ | {
442
+ /** The query parameter that carries the key. */
443
+ readonly query: string;
444
+ }
445
+ | undefined;
380
446
  /** The endpoint used when the caller names none. @defaultValue null */
381
447
  readonly defaultEndpoint?: string | null | undefined;
382
448
  /** Where it runs; a runtime marked unsupported is refused with E_SOURCE_RUNTIME before any request. */
@@ -584,6 +650,8 @@ export interface SourceReportInfo {
584
650
  | undefined;
585
651
  /** What lets a later call tell whether the data changed. */
586
652
  readonly validators?: SourceValidators | undefined;
653
+ /** What the source holds for this load, when it counted: the nodes and edges it matches. */
654
+ readonly total?: SourceTotal | undefined;
587
655
  }
588
656
 
589
657
  /**
@@ -33,12 +33,21 @@ export interface AnnotationBase {
33
33
  readonly z: number;
34
34
  }
35
35
 
36
+ /**
37
+ * How far an annotation is turned about its box's center, in degrees, clockwise as seen on screen (0: not turned).
38
+ * Shapes, texts and pictures carry it; Cytoscape saves it as `rotation`.
39
+ */
40
+ interface RotatedAnnotation {
41
+ /** The turn in degrees, clockwise on screen. */
42
+ readonly rotation: number;
43
+ }
44
+
36
45
  /**
37
46
  * A filled, outlined shape.
38
47
  * @category Styles
39
48
  */
40
- export interface ShapeAnnotation extends AnnotationBase {
41
- /** Which kind of annotation this is: always "shape". */
49
+ export interface ShapeAnnotation extends AnnotationBase, RotatedAnnotation {
50
+ /** What the annotation is: always `"shape"` for a shape. */
42
51
  readonly kind: "shape";
43
52
  /** The box's center. */
44
53
  readonly center: AnnotationPoint;
@@ -64,8 +73,8 @@ export interface ShapeAnnotation extends AnnotationBase {
64
73
  * A line of text.
65
74
  * @category Styles
66
75
  */
67
- export interface TextAnnotation extends AnnotationBase {
68
- /** Which kind of annotation this is: always "text". */
76
+ export interface TextAnnotation extends AnnotationBase, RotatedAnnotation {
77
+ /** What the annotation is: always `"text"` for a line of text. */
69
78
  readonly kind: "text";
70
79
  /** The text. */
71
80
  readonly text: string;
@@ -92,7 +101,7 @@ export interface TextAnnotation extends AnnotationBase {
92
101
  * @category Styles
93
102
  */
94
103
  export interface ArrowAnnotation extends AnnotationBase {
95
- /** Which kind of annotation this is: always "arrow". */
104
+ /** What the annotation is: always `"arrow"` for an arrow. */
96
105
  readonly kind: "arrow";
97
106
  /** Where the line starts. */
98
107
  readonly from: AnnotationPoint;
@@ -112,6 +121,46 @@ export interface ArrowAnnotation extends AnnotationBase {
112
121
  readonly sourceSize: number;
113
122
  /** The end's arrowhead size as a factor of the normal size. */
114
123
  readonly targetSize: number;
124
+ /** The arrowhead color at the start. */
125
+ readonly sourceColor: StyleColor;
126
+ /** The arrowhead color at the end. */
127
+ readonly targetColor: StyleColor;
128
+ /**
129
+ * How long the start's arrowhead is along the line, in the units of the points, size included; absent, the
130
+ * drawing program's own length for the line's width.
131
+ */
132
+ readonly sourceHeadLength?: number;
133
+ /** How wide the start's arrowhead is across the line, as `sourceHeadLength` says. */
134
+ readonly sourceHeadWidth?: number;
135
+ /** How long the end's arrowhead is along the line, as `sourceHeadLength` says. */
136
+ readonly targetHeadLength?: number;
137
+ /** How wide the end's arrowhead is across the line, as `sourceHeadLength` says. */
138
+ readonly targetHeadWidth?: number;
139
+ }
140
+
141
+ /**
142
+ * A picture placed in a box, which `readImageAnnotations()` reads.
143
+ * @category Styles
144
+ */
145
+ export interface ImageAnnotation extends AnnotationBase, RotatedAnnotation {
146
+ /** What the annotation is: always `"image"` for a picture. */
147
+ readonly kind: "image";
148
+ /** The box's center. */
149
+ readonly center: AnnotationPoint;
150
+ /** The box's width; the picture is stretched to it. */
151
+ readonly width: number;
152
+ /** The box's height. */
153
+ readonly height: number;
154
+ /** Where the picture is, as the file names it. */
155
+ readonly url: string;
156
+ /** The picture's opacity, 0..1. */
157
+ readonly opacity: number;
158
+ /** The outline's color. */
159
+ readonly borderColor: StyleColor;
160
+ /** The outline's opacity, 0..1 (0 draws none). */
161
+ readonly borderOpacity: number;
162
+ /** The outline's width (0 draws none). */
163
+ readonly borderWidth: number;
115
164
  }
116
165
 
117
166
  /**
@@ -151,11 +200,13 @@ const SHAPES: ReadonlyMap<string, StyleNodeShape> = new Map<string, StyleNodeSha
151
200
  ["parallelogram", "parallelogram"],
152
201
  ["star5", "star"],
153
202
  ["star6", "star"],
203
+ ["v", "vee"],
154
204
  ]);
155
205
 
156
206
  /**
157
- * Cytoscape's annotation arrowheads, by the position in its `ArrowType` list (older sessions) and by name (newer
158
- * ones), lowercase.
207
+ * Cytoscape's annotation arrowheads, by the number it saves (the declaration order of ding's
208
+ * `ArrowAnnotationImpl.ArrowType` in 3.10: Circle, Closed Arrow, Concave Arrow, Diamond, Open Arrow, No Arrow,
209
+ * X Arrow, Triangular Head, T-Shape) and by its display name, lowercase.
159
210
  */
160
211
  const ARROW_ORDER: readonly StyleArrowShape[] = [
161
212
  "circle",
@@ -164,13 +215,18 @@ const ARROW_ORDER: readonly StyleArrowShape[] = [
164
215
  "diamond",
165
216
  "triangle-open",
166
217
  "none",
167
- "tee",
168
- "triangle",
169
- "triangle",
218
+ "other:x",
170
219
  "triangle",
171
220
  "tee",
172
- "other:x",
173
221
  ];
222
+ /**
223
+ * How long along its line each of Cytoscape's annotation arrowheads is drawn at size 1, by its `ArrowType` position,
224
+ * every one 10 wide whatever the line's width (measured on Cytoscape 3.10.5's SVG of `specimen-images-charts-p6`):
225
+ * the Closed, Concave, Diamond and Open Arrows 17, the Circle and the X 10, the Triangular Head 5, the T a bar across.
226
+ */
227
+ const ARROW_LENGTHS: readonly number[] = [10, 17, 17, 17, 17, 0, 10, 5, 0];
228
+ /** How wide across its line every Cytoscape annotation arrowhead is at size 1. */
229
+ const ARROW_WIDTH = 10;
174
230
  const ARROW_NAMES: ReadonlyMap<string, StyleArrowShape> = new Map<string, StyleArrowShape>([
175
231
  ["circle", "circle"],
176
232
  ["closed arrow", "triangle"],
@@ -181,7 +237,10 @@ const ARROW_NAMES: ReadonlyMap<string, StyleArrowShape> = new Map<string, StyleA
181
237
  ["pipe", "tee"],
182
238
  ["triangle", "triangle"],
183
239
  ["t", "tee"],
240
+ ["t-shape", "tee"],
241
+ ["triangular head", "triangle"],
184
242
  ["x", "other:x"],
243
+ ["x arrow", "other:x"],
185
244
  ]);
186
245
 
187
246
  /**
@@ -209,6 +268,49 @@ export function readAnnotations(snapshot: GraphSnapshot): FileAnnotations {
209
268
  return { annotations, skipped: [...skipped] };
210
269
  }
211
270
 
271
+ /**
272
+ * The pictures a graph's annotations place, from the column Cytoscape desktop keeps them in: the annotations
273
+ * `readAnnotations()` lists as skipped `ImageAnnotation`s.
274
+ * @param snapshot - the graph
275
+ * @returns the pictures, in the file's order; none when the graph has none
276
+ * @category Styles
277
+ */
278
+ export function readImageAnnotations(snapshot: GraphSnapshot): ImageAnnotation[] {
279
+ const { graph } = snapshot;
280
+ const cell = graph.has(CYTOSCAPE_ANNOTATIONS_COLUMN) ? graph.value(CYTOSCAPE_ANNOTATIONS_COLUMN, 0) : null;
281
+ return cellStrings(cell).flatMap((entry, i) => {
282
+ const f = parseEntry(entry);
283
+ const url = f.get("URL") ?? "";
284
+ if ((f.get("type") ?? "").replace(TYPE_PREFIX, "") !== "ImageAnnotation" || url === "") {
285
+ return [];
286
+ }
287
+ const zoom = positive(f.get("zoom")) ?? 1;
288
+ const x = num(f.get("x")) ?? 0;
289
+ const y = num(f.get("y")) ?? 0;
290
+ const width = (positive(f.get("width")) ?? 0) / zoom;
291
+ const height = (positive(f.get("height")) ?? 0) / zoom;
292
+ const border = javaColor(f.get("edgeColor")) ?? { color: "#000000", alpha: 1 };
293
+ const opacity = num(f.get("opacity"));
294
+ return [
295
+ {
296
+ id: f.get("uuid") ?? String(i),
297
+ layer: f.get("canvas") === "background" ? "background" : "foreground",
298
+ z: num(f.get("z")) ?? 0,
299
+ kind: "image",
300
+ rotation: num(f.get("rotation")) ?? 0,
301
+ center: { x: x + width / 2, y: -(y + height / 2) },
302
+ width,
303
+ height,
304
+ url,
305
+ opacity: opacity === null ? 1 : Math.min(1, Math.max(0, opacity)),
306
+ borderColor: border.color,
307
+ borderOpacity: border.alpha * percent(f.get("edgeOpacity")),
308
+ borderWidth: (num(f.get("edgeThickness")) ?? 0) / zoom,
309
+ },
310
+ ];
311
+ });
312
+ }
313
+
212
314
  /**
213
315
  * A cell's strings: a list cell's items, or the lines of a text cell.
214
316
  * @param cell - the cell
@@ -292,6 +394,7 @@ function shapeOf(f: ReadonlyMap<string, string>, base: AnnotationBase, zoom: num
292
394
  return {
293
395
  ...base,
294
396
  kind: "shape",
397
+ rotation: num(f.get("rotation")) ?? 0,
295
398
  center: { x: x + width / 2, y: -(y + height / 2) },
296
399
  width,
297
400
  height,
@@ -326,6 +429,7 @@ function textOf(
326
429
  return {
327
430
  ...base,
328
431
  kind: "text",
432
+ rotation: num(f.get("rotation")) ?? 0,
329
433
  text: f.get("text") ?? "",
330
434
  at,
331
435
  anchor,
@@ -340,9 +444,11 @@ function textOf(
340
444
 
341
445
  /**
342
446
  * An arrow annotation. Cytoscape keeps its start as the annotation it leaves (`sourceAnnotation`) and its end as a
343
- * point, a node's center at save time (`targetNode`) or another annotation, and saves the arrow's top-left corner
344
- * as `x`, `y`: the start wherever the end lies right of and below it, which is taken for the start, else the center
345
- * of the annotation it leaves.
447
+ * point (`targetPoint`), a node's center at save time (`targetNode`) or another annotation (`targetAnnotation`). It
448
+ * draws the line from the middle of the side of the source annotation's box that faces the end, to the end point or
449
+ * the middle of the facing side of the target annotation's box, at half the saved `lineThickness` and never under
450
+ * 1 (measured on Cytoscape 3.10.5's SVG of `specimen-images-charts-p6` and of the tutorial session). A source with
451
+ * no saved size (a text annotation) leaves from the arrow's saved `x`, `y` corner.
346
452
  * @param f - its fields
347
453
  * @param base - its id, layer and order
348
454
  * @param zoom - the zoom its line width was saved at
@@ -355,17 +461,26 @@ function arrowOf(
355
461
  zoom: number,
356
462
  byId: ReadonlyMap<string, ReadonlyMap<string, string>>,
357
463
  ): ArrowAnnotation[] | null {
358
- const target = f.get("targetAnnotation");
359
- const to = point(f.get("targetPoint")) ?? point(f.get("targetNode")) ?? centerOf(byId.get(target ?? ""), zoom);
360
- if (to === null) {
464
+ const sourceBox = boxOf(byId.get(f.get("sourceAnnotation") ?? ""), zoom);
465
+ const targetBox = boxOf(byId.get(f.get("targetAnnotation") ?? ""), zoom);
466
+ const toPoint = point(f.get("targetPoint")) ?? point(f.get("targetNode"));
467
+ const corner = { x: num(f.get("x")) ?? 0, y: num(f.get("y")) ?? 0 };
468
+ const sourceCenter = sourceBox === null ? corner : centerOfBox(sourceBox);
469
+ const aim = toPoint ?? (targetBox === null ? null : centerOfBox(targetBox));
470
+ if (aim === null) {
361
471
  return null;
362
472
  }
363
- const corner = { x: num(f.get("x")) ?? 0, y: num(f.get("y")) ?? 0 };
364
- const source = centerOf(byId.get(f.get("sourceAnnotation") ?? ""), zoom) ?? corner;
365
- // ponytail: the start is exact only when the end lies right of and below it; elsewhere the center of the
366
- // annotation it leaves, as Cytoscape stores no other start. Clip to that annotation's box if it matters.
367
- const from = { x: to.x > corner.x ? corner.x : source.x, y: to.y > corner.y ? corner.y : source.y };
473
+ // a source with no saved size (a text) leaves from the arrow's saved top-left corner where the end lies right of
474
+ // and below it, else from the source's corner: the file keeps no other trace of where the text was drawn
475
+ const from =
476
+ sourceBox !== null && sourceBox.width > 0 && sourceBox.height > 0
477
+ ? facing(sourceBox, aim)
478
+ : { x: aim.x > corner.x ? corner.x : sourceCenter.x, y: aim.y > corner.y ? corner.y : sourceCenter.y };
479
+ // ponytail: a node end stops at its center; Cytoscape stops at the node's box, which needs the node's size
480
+ const to = toPoint ?? facing(targetBox ?? { x: aim.x, y: aim.y, width: 0, height: 0 }, sourceCenter);
368
481
  const color = javaColor(f.get("lineColor")) ?? { color: "#000000", alpha: 1 };
482
+ const sourceColor = javaColor(f.get("sourceColor"))?.color ?? color.color;
483
+ const targetColor = javaColor(f.get("targetColor"))?.color ?? color.color;
369
484
  return [
370
485
  {
371
486
  ...base,
@@ -374,22 +489,55 @@ function arrowOf(
374
489
  to: { x: to.x, y: -to.y },
375
490
  color: color.color,
376
491
  opacity: color.alpha * percent(f.get("lineOpacity")),
377
- width: (positive(f.get("lineThickness")) ?? 1) / zoom,
492
+ width: Math.max(1, (positive(f.get("lineThickness")) ?? 1) / zoom / 2),
378
493
  sourceArrow: arrowShape(f.get("sourceType")),
379
494
  targetArrow: arrowShape(f.get("targetType")),
380
495
  sourceSize: positive(f.get("sourceSize")) ?? 1,
381
496
  targetSize: positive(f.get("targetSize")) ?? 1,
497
+ sourceColor,
498
+ targetColor,
499
+ ...heads("source", f.get("sourceType"), positive(f.get("sourceSize")) ?? 1),
500
+ ...heads("target", f.get("targetType"), positive(f.get("targetSize")) ?? 1),
382
501
  },
383
502
  ];
384
503
  }
385
504
 
386
505
  /**
387
- * An annotation's center, y down as the file writes it: a shape's box center, a text's corner.
506
+ * The length and width Cytoscape draws one end's arrowhead at: its type's length and 10 across, times its size.
507
+ * @param end - which end
508
+ * @param type - the end's saved `ArrowType`, a position or a name
509
+ * @param size - the end's saved size
510
+ * @returns the end's head length and width, none for an end without a head
511
+ */
512
+ function heads(
513
+ end: "source" | "target",
514
+ type: string | undefined,
515
+ size: number,
516
+ ): Partial<Pick<ArrowAnnotation, "sourceHeadLength" | "sourceHeadWidth" | "targetHeadLength" | "targetHeadWidth">> {
517
+ const shape = arrowShape(type);
518
+ if (shape === "none") {
519
+ return {};
520
+ }
521
+ const k = num(type) ?? ARROW_ORDER.indexOf(shape);
522
+ const length = ARROW_LENGTHS[k] ?? ARROW_LENGTHS[1];
523
+ return { [`${end}HeadLength`]: length * size, [`${end}HeadWidth`]: ARROW_WIDTH * size };
524
+ }
525
+
526
+ /** An annotation's box as the file writes it: top-left corner, y down. */
527
+ interface FileBox {
528
+ readonly x: number;
529
+ readonly y: number;
530
+ readonly width: number;
531
+ readonly height: number;
532
+ }
533
+
534
+ /**
535
+ * An annotation's box, y down as the file writes it.
388
536
  * @param f - its fields, or undefined
389
537
  * @param zoom - the zoom the arrow was saved at
390
- * @returns the point, or null
538
+ * @returns the box, or null
391
539
  */
392
- function centerOf(f: ReadonlyMap<string, string> | undefined, zoom: number): AnnotationPoint | null {
540
+ function boxOf(f: ReadonlyMap<string, string> | undefined, zoom: number): FileBox | null {
393
541
  if (f === undefined) {
394
542
  return null;
395
543
  }
@@ -398,7 +546,33 @@ function centerOf(f: ReadonlyMap<string, string> | undefined, zoom: number): Ann
398
546
  if (x === null || y === null) {
399
547
  return null;
400
548
  }
401
- return { x: x + (positive(f.get("width")) ?? 0) / zoom / 2, y: y + (positive(f.get("height")) ?? 0) / zoom / 2 };
549
+ return { x, y, width: (positive(f.get("width")) ?? 0) / zoom, height: (positive(f.get("height")) ?? 0) / zoom };
550
+ }
551
+
552
+ /**
553
+ * A box's center.
554
+ * @param b - the box
555
+ * @returns the center
556
+ */
557
+ function centerOfBox(b: FileBox): AnnotationPoint {
558
+ return { x: b.x + b.width / 2, y: b.y + b.height / 2 };
559
+ }
560
+
561
+ /**
562
+ * The middle of the side of a box that faces a point: a left or right side when the point lies more across than
563
+ * along, against the box's own proportions, else the top or bottom.
564
+ * @param b - the box
565
+ * @param p - the point
566
+ * @returns the side's middle
567
+ */
568
+ function facing(b: FileBox, p: AnnotationPoint): AnnotationPoint {
569
+ const c = centerOfBox(b);
570
+ const dx = p.x - c.x;
571
+ const dy = p.y - c.y;
572
+ if (Math.abs(dx) * b.height >= Math.abs(dy) * b.width) {
573
+ return { x: c.x + Math.sign(dx) * (b.width / 2), y: c.y };
574
+ }
575
+ return { x: c.x, y: c.y + Math.sign(dy) * (b.height / 2) };
402
576
  }
403
577
 
404
578
  /**