@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
@@ -1,33 +1,43 @@
1
1
  /**
2
2
  * Pajek styles: each vertex's shape keyword and drawing parameters (`ic`, `bc`, `bw`, `x_fact`, `y_fact`, `lc`, `fos`)
3
- * and each line's `c`, `w` and `p`, read the way Pajek draws them, with Pajek's stated defaults beneath (an ellipse,
4
- * black solid lines, an arrow at the target of every arc). Colors are Pajek's: the dvips names, `GrayNN`,
5
- * `RGBrrggbb`, `RGB(r,g,b)` and the CMYK forms. `x_fact` and `y_fact` are factors of Pajek's normal vertex size, so the
6
- * lengths are relative.
3
+ * and each line's `c`, `w` and `p`, read the way Pajek 6.02 draws them (parameters carried from line to line, `CARRIED`),
4
+ * with Pajek's own defaults beneath (a #ffd9bc ellipse with a #660000 border, grey arcs with an arrow at the target,
5
+ * teal edges). Colors are Pajek's: the dvips names and the ten Pajek adds, `GrayNN`, `RGBrrggbb`, `RGB(r,g,b)` and the
6
+ * CMYK forms. Lengths are in PostScript points, the unit of Pajek's EPS and SVG export, where the drawing's [0,1] square
7
+ * is [0,500] (`PAJEK_POINTS_PER_UNIT`): a vertex is Pajek's normal size 20 times its `x_fact` and `y_fact`,
8
+ * `bw` and `fos` are points as written, an arc is `w` wide and an edge twice `w`.
7
9
  *
8
10
  * Writing: the same parameters from what graphty draws, leaving out what Pajek draws by default; a color that is a
9
11
  * dvips name is written by name, any other as `RGBrrggbb`, so colors are exact. The `graphty.styles` block, with the
10
12
  * per-element values its rules read inside it (Pajek has no other place for them), is one comment line,
11
13
  * `% graphty.styles <json>`, which Pajek skips and graph-io reads back.
12
14
  */
15
+ import { explicitWeights } from "../../common/weights.js";
13
16
  import { canonColor, colorOpacity } from "../../styles/canon/color.js";
14
17
  import { DVIPS_COLORS } from "../../styles/canon/color-tables.js";
15
18
  import { canonEnum } from "../../styles/canon/enums.js";
16
19
  import { canonNumber } from "../../styles/canon/number.js";
20
+ import { noteAt } from "../../styles/canon/site.js";
17
21
  import { canonText } from "../../styles/canon/text.js";
22
+ import { STYLE_ISSUE } from "../../styles/codes.js";
23
+ import { toolDefaults } from "../../styles/defaults.js";
18
24
  import { StyleApproximations } from "../../styles/io/approximations.js";
19
- import { blockStyles, parseStyleBlock, styleBlockLosses, writeStyleBlock } from "../../styles/io/block.js";
25
+ import { styleBlockLosses, writeStyleBlock } from "../../styles/io/block.js";
26
+ import { elementValues, takeFromBlock } from "../../styles/io/round-trip.js";
20
27
  import { StyleNotes } from "../../styles/notes.js";
21
- import { styleFingerprint } from "../../styles/plan/features.js";
22
- import { plainCell, resolveStyles } from "../../styles/plan/resolve.js";
28
+ import { plainCell } from "../../styles/plan/resolve.js";
29
+ import { graphvizFontName, postscriptFont } from "../dot/drawing.js";
23
30
  import { valueColumns } from "../graphml/styles-yed.js";
24
- import { LABEL_COLUMN, PAJEK_STYLE_COMMENT, SHAPE_COLUMN } from "./syntax.js";
31
+ import { drawLines, drawsLineLabels, drawVertices } from "./draw.js";
32
+ import { LABEL_COLUMN, PAJEK_STYLE_COMMENT, SHAPE_COLUMN, VALUE_COLUMN } from "./syntax.js";
25
33
  /**
26
- * What the Pajek writer holds natively: the vertex label, the vertex shape keyword and drawing parameters, the line
34
+ * What the Pajek writer holds natively: the vertex label, the vertex shape keyword (a polygon only as Pajek's diamond,
35
+ * `shapePoints` with its `q`) and drawing parameters, the line
27
36
  * parameters, and the arrows Pajek draws on arcs. The `graphty.styles` block is a comment line the writer places itself.
28
37
  * @category Built-in formats
29
38
  */
30
39
  export const PAJEK_STYLE_CAPABILITIES = Object.freeze({
40
+ tool: "pajek",
31
41
  node: Object.freeze([
32
42
  "label",
33
43
  "fill",
@@ -36,23 +46,130 @@ export const PAJEK_STYLE_CAPABILITIES = Object.freeze({
36
46
  "borderColor",
37
47
  "borderWidth",
38
48
  "shape",
49
+ "shapePoints",
39
50
  "width",
40
51
  "height",
41
52
  "labelColor",
42
53
  "labelSize",
54
+ "labelFont",
55
+ "labelPosition",
56
+ "labelOffsetX",
57
+ "labelOffsetY",
58
+ "labelShiftX",
59
+ ]),
60
+ edge: Object.freeze([
61
+ "color",
62
+ "opacity",
63
+ "width",
64
+ "lineStyle",
65
+ "sourceArrow",
66
+ "targetArrow",
67
+ "arrowPosition",
68
+ "label",
69
+ "labelColor",
70
+ "labelSize",
71
+ "labelFont",
43
72
  ]),
44
- edge: Object.freeze(["color", "opacity", "width", "lineStyle", "sourceArrow", "targetArrow"]),
45
73
  block: "native",
46
74
  });
47
75
  /**
48
- * Pajek's default vertex size, in the units of a border width `bw`: `x_fact` and `y_fact` are factors of it, so a
49
- * border width is read as a factor of it too (`bw 1`, Pajek's default, is a fifth of a normal vertex).
76
+ * Pajek's normal vertex size, in points: what `x_fact` and `y_fact` multiply (the manual, p. 89, names `x_fact` and
77
+ * `y_fact` "magnification" without stating the value).
78
+ * Measured in Pajek 6.02's own SVG export (`test/fidelity/oracles/pajek-*.svg`): a vertex with no size parameter is
79
+ * drawn 20 across, and `x_fact 1.54` 30.8, on the drawing's [0,500] square.
50
80
  */
51
- const VERTEX_SIZE = 5;
81
+ const PAJEK_VERTEX_SIZE = 20;
82
+ /**
83
+ * How far past its vertex size Pajek draws its man and woman figures, across and up: Pajek 6.02's SVG export draws
84
+ * them as paths that reach beyond the vertex's own square, a man 2.5 times its size across and 6.49 times its size
85
+ * tall, a woman (her skirt and arms wider) 3 times across and 6.48 tall (`pajek-specimen-node-shapes`, vertices 9 and
86
+ * 10 at `x_fact 0.5`: the man's path spans x -12.51..12.51 and y -32.74..32.13, the woman's -15.02..15.02 and
87
+ * -32.99..31.79, around a size of 10).
88
+ */
89
+ const PAJEK_FIGURES = new Map([
90
+ ["other:man", [2.502, 6.487]],
91
+ ["other:woman", [3.003, 6.478]],
92
+ ]);
93
+ /**
94
+ * Points per coordinate unit: "When Postscript picture is obtained, the square [0,1]x[0,1] is transformed to
95
+ * [0,500]x[0,500]" (Pajek, "Pajek to EPS", http://mrvar.fdv.uni-lj.si/pajek/DrawEPS.htm).
96
+ */
97
+ export const PAJEK_POINTS_PER_UNIT = 500;
52
98
  /** The vertex parameters read as styles. */
53
- const NODE_KEYS = ["ic", "bc", "bw", "x_fact", "y_fact", "lc", "fos"];
99
+ const NODE_KEYS = [
100
+ "ic",
101
+ "bc",
102
+ "bw",
103
+ "s_size",
104
+ "x_fact",
105
+ "y_fact",
106
+ "phi",
107
+ "q",
108
+ "lc",
109
+ "fos",
110
+ "font",
111
+ "lr",
112
+ "lphi",
113
+ "la",
114
+ ];
54
115
  /** The line parameters read as styles. */
55
- const EDGE_KEYS = ["c", "w", "p"];
116
+ const EDGE_KEYS = ["c", "w", "p", "s", "ap", "l", "lc", "fos", "font"];
117
+ /**
118
+ * What Pajek carries from one line of a section to the next. A line (arc or edge) that does not set one of these
119
+ * parameters is drawn with the value the line before it set. A vertex line that sets no parameter and names no shape
120
+ * is drawn exactly as the vertex line before it; a vertex line that sets any starts again from Pajek's defaults.
121
+ * Measured in Pajek 6.02's own SVG export: `test/fidelity/oracles/pajek-kdorola.svg` (vertices 2 to 59, which set
122
+ * nothing, drawn with vertex 1's `lr 11 lphi 285 fos 9`, and 61 on as vertex 60's `box`), `pajek-1crn.svg` (vertex 3
123
+ * drawn as vertex 2), `pajek-synth-lines.svg` (arc 3, which sets `w 3` but no `c`, drawn in arc 2's `c Blue`), and
124
+ * the generated `shapes-and-lines.net` (vertex 5 at the default size after vertex 4's `x_fact 8`). A line's label `l`
125
+ * is its own; its label's color, size and font are not carried here, as they only show with a label.
126
+ */
127
+ const CARRIED = {
128
+ node: [SHAPE_COLUMN, ...NODE_KEYS],
129
+ edge: ["c", "w", "p", "s", "ap"],
130
+ };
131
+ /**
132
+ * What Pajek 6.02 carries from line to line as it reads: not the pattern `p`, which the writer still restates
133
+ * (`pajek-synth-lines`: edge `3 10` after `1 8 ... p Dots` and arc `5 6 -1` after a `p Solid` are drawn as if no line
134
+ * before set one).
135
+ */
136
+ const CARRIED_LINE = CARRIED.edge.filter((key) => key !== "p");
137
+ /** The width Pajek draws an edge (undirected) at for each unit of `w`; an arc is drawn `w` wide. */
138
+ const EDGE_WIDTH_PER_W = 2;
139
+ /** The color and width Pajek draws an arc with when it sets no `c` or `w` (an edge's are the tool defaults). */
140
+ const ARC_DEFAULTS = { color: "#999999", width: 1 };
141
+ /**
142
+ * A getter that gives an element the parameters an element before it set, as Pajek reads them: for a line each
143
+ * parameter it leaves out, for a vertex all of them when it sets none (`CARRIED`).
144
+ * @param keys - the parameters carried
145
+ * @param whole - true for vertices: carried only to an element that sets none, and then all together
146
+ * @returns for each element in order, its getter
147
+ */
148
+ function carriedParams(keys, whole) {
149
+ let last = new Map();
150
+ return (get) => {
151
+ const own = new Map();
152
+ for (const key of keys) {
153
+ const v = get(key);
154
+ if (v !== null) {
155
+ own.set(key, v);
156
+ }
157
+ }
158
+ if (whole) {
159
+ if (own.size > 0) {
160
+ last = own;
161
+ return get;
162
+ }
163
+ }
164
+ else {
165
+ for (const [key, v] of own) {
166
+ last.set(key, v);
167
+ }
168
+ }
169
+ const carried = last;
170
+ return (key) => get(key) ?? (keys.includes(key) ? (carried.get(key) ?? null) : null);
171
+ };
172
+ }
56
173
  /** The style column marking arcs, which Pajek draws with an arrow at the target. */
57
174
  const DIRECTED_KEY = "directed";
58
175
  /** The properties the reader reads, per target: what a file graphty wrote can bring back from its block. */
@@ -60,6 +177,8 @@ const READ = {
60
177
  node: [
61
178
  "label",
62
179
  "shape",
180
+ "shapePoints",
181
+ "shapePointsStretch",
63
182
  "fill",
64
183
  "fillOpacity",
65
184
  "borderColor",
@@ -68,8 +187,25 @@ const READ = {
68
187
  "height",
69
188
  "labelColor",
70
189
  "labelSize",
190
+ "labelFont",
191
+ "labelPosition",
192
+ "labelOffsetX",
193
+ "labelOffsetY",
194
+ "labelShiftX",
195
+ "labelRotation",
196
+ ],
197
+ edge: [
198
+ "color",
199
+ "opacity",
200
+ "width",
201
+ "lineStyle",
202
+ "arrowSize",
203
+ "arrowPosition",
204
+ "label",
205
+ "labelColor",
206
+ "labelSize",
207
+ "labelFont",
71
208
  ],
72
- edge: ["color", "opacity", "width", "lineStyle"],
73
209
  };
74
210
  /**
75
211
  * Reads a Pajek color and its alpha.
@@ -85,6 +221,13 @@ function readColor(raw, property, opacity, put, at) {
85
221
  }
86
222
  const c = canonColor(raw, "dvips", at(property));
87
223
  if (c === null) {
224
+ // a name Pajek does not know, or a known one in another case (`red`), fills a vertex white and draws a line
225
+ // black (`pajek-specimen-node-fills-borders-p3` `ic-unknown-name`, `ic-lowercase-name`); ponytail: measured
226
+ // on names in `ic` and `c` only, so a border or label color and an unreadable RGB / CMYK form keep the default
227
+ const unknown = UNKNOWN_COLORS.get(property);
228
+ if (unknown !== undefined && typeof raw === "string" && /^[A-Za-z]\w*$/.test(raw.trim())) {
229
+ put(property, unknown);
230
+ }
88
231
  return;
89
232
  }
90
233
  put(property, c.color);
@@ -93,6 +236,11 @@ function readColor(raw, property, opacity, put, at) {
93
236
  put(opacity, alpha);
94
237
  }
95
238
  }
239
+ /** What Pajek draws for a color it cannot read, by property. */
240
+ const UNKNOWN_COLORS = new Map([
241
+ ["fill", "#ffffff"],
242
+ ["color", "#000000"],
243
+ ]);
96
244
  /**
97
245
  * Reads a length or factor.
98
246
  * @param raw - the parameter's value, or null
@@ -110,41 +258,686 @@ function readNumber(raw, property, put, at) {
110
258
  * @param get - the vertex's parameters
111
259
  * @param put - receives the values
112
260
  * @param at - the sites
261
+ * @param place - the vertex's place in the file's coordinates, or null when it has none
113
262
  */
114
- function readVertex(get, put, at) {
263
+ function readVertex(get, put, at, place = null) {
115
264
  // an empty label draws nothing
116
265
  const label = get(LABEL_COLUMN);
117
266
  if (label !== null && label !== "") {
118
267
  put("label", canonText(label, at("label")));
119
268
  }
120
- const shape = get(SHAPE_COLUMN);
121
- if (shape !== null) {
122
- put("shape", canonEnum("shape", shape, "dvips", at("shape")));
269
+ const raw = get(SHAPE_COLUMN);
270
+ const shape = raw === null ? null : canonEnum("shape", raw, "dvips", at("shape"));
271
+ if (raw !== null) {
272
+ put("shape", shape);
123
273
  }
124
274
  readColor(get("ic"), "fill", "fillOpacity", put, at);
125
275
  readColor(get("bc"), "borderColor", null, put, at);
126
- const bw = get("bw");
127
- if (bw !== null) {
128
- const width = canonNumber(bw, at("borderWidth"));
129
- put("borderWidth", width === null ? null : width / VERTEX_SIZE);
130
- }
131
- readNumber(get("x_fact"), "width", put, at);
132
- readNumber(get("y_fact"), "height", put, at);
276
+ readNumber(get("bw"), "borderWidth", put, at);
277
+ readSize(get, put, at, PAJEK_FIGURES.get(String(shape)));
278
+ readOutline(get, put, shape);
133
279
  readColor(get("lc"), "labelColor", null, put, at);
134
280
  readNumber(get("fos"), "labelSize", put, at);
281
+ readFont(get("font"), put, at);
282
+ readLabelPosition(get, put, at);
283
+ readLabelAngle(get("la"), put, at, place);
284
+ if (shape === "none") {
285
+ // an `empty` vertex's label is drawn white at size 1 on its center, whatever the line sets
286
+ // (`pajek-synth-vertices` `empty *`, `pajek-lin-rel4` v226 to v233)
287
+ for (const [property, value] of EMPTY_LABEL) {
288
+ put(property, value);
289
+ }
290
+ }
291
+ }
292
+ /**
293
+ * The corners Pajek 6.02's SVG export draws a box, a triangle and a house with, as `shapePoints` (fractions of the half
294
+ * width and height, y up): `pajek-specimen-node-shapes`, `shape-box`, `shape-triangle`, `shape-house`.
295
+ */
296
+ const PAJEK_OUTLINES = new Map([
297
+ [
298
+ "rectangle",
299
+ [
300
+ [-1, 1],
301
+ [1, 1],
302
+ [1, -1],
303
+ [-1, -1],
304
+ ],
305
+ ],
306
+ [
307
+ "triangle",
308
+ [
309
+ [1, -1],
310
+ [0, 1],
311
+ [-1, -1],
312
+ ],
313
+ ],
314
+ [
315
+ "other:house",
316
+ [
317
+ [-0.7, -1],
318
+ [0.7, -1],
319
+ [0.7, 0.3],
320
+ [1, 0.3],
321
+ [1, 0.4],
322
+ [0, 1],
323
+ [-1, 0.4],
324
+ [-1, 0.3],
325
+ [-0.7, 0.3],
326
+ ],
327
+ ],
328
+ ]);
329
+ /** A diamond's `q` where the line sets none (Pajek's shipped SHAPES.CFG). */
330
+ const PAJEK_DIAMOND_Q = 0.001;
331
+ /**
332
+ * A vertex's outline where Pajek draws one no named shape is: a diamond is Pajek's six-cornered one, its top and bottom
333
+ * cut `q` of its half width wide (`pajek-specimen-node-shapes`: `q 0.001` by default, `q 0.5` a hexagon, `q 1` a
334
+ * square, `q 2` a bow tie twice as wide), and `phi` turns a box, a triangle, a house or a diamond `phi` degrees
335
+ * counterclockwise about its center (`phi-30-box`, `phi-90-triangle`: Pajek draws the shape at its size, then turns
336
+ * it). ponytail: the corners are fractions of the size the line gives (`x_fact`, `y_fact`); a turned shape whose width
337
+ * and height the Draw window's Size of Vertices or vectors scale apart is turned in the wrong box. A turned ellipse,
338
+ * man or woman is drawn unturned: an outline of corners would draw an ellipse as a polygon.
339
+ * @param get - the vertex's parameters
340
+ * @param put - receives the values
341
+ * @param shape - its shape
342
+ */
343
+ function readOutline(get, put, shape) {
344
+ const phi = numberOrNull(get("phi")) ?? 0;
345
+ const q = numberOrNull(get("q")) ?? PAJEK_DIAMOND_Q;
346
+ const diamond = [
347
+ [-1, 0],
348
+ [-q, 1],
349
+ [q, 1],
350
+ [1, 0],
351
+ [q, -1],
352
+ [-q, -1],
353
+ ];
354
+ const corners = shape === "diamond" ? diamond : PAJEK_OUTLINES.get(String(shape));
355
+ if (corners === undefined || (shape !== "diamond" && phi % 360 === 0)) {
356
+ return;
357
+ }
358
+ // turned in the drawn box, x_fact by y_fact, and back to fractions of it
359
+ const [w, h] = [numberOrNull(get("x_fact")) || 1, numberOrNull(get("y_fact")) || 1];
360
+ const [c, s] = [Math.cos((phi * Math.PI) / 180), Math.sin((phi * Math.PI) / 180)];
361
+ const round = (v) => String(Number(v.toFixed(4)) + 0);
362
+ const points = corners.map(([x, y]) => {
363
+ const [px, py] = [x * w, y * h];
364
+ return `${round((px * c - py * s) / w)},${round((px * s + py * c) / h)}`;
365
+ });
366
+ put("shape", "polygon");
367
+ put("shapePoints", points.join(" "));
368
+ put("shapePointsStretch", false);
369
+ }
370
+ /** How Pajek 6.02's SVG export draws an `empty` vertex's label. */
371
+ const EMPTY_LABEL = [
372
+ ["labelSize", 1],
373
+ ["labelColor", "#ffffff"],
374
+ ["labelPosition", "center"],
375
+ ["labelOffsetX", 0],
376
+ ["labelOffsetY", 0],
377
+ ["labelShiftX", 0],
378
+ ];
379
+ /**
380
+ * A label's `font`: Pajek writes it into its SVG export as the family, as given, so a PostScript name (`Courier-Bold`,
381
+ * `Helvetica-Oblique`) is drawn in its family, with a generic one after it, and upright, as the pinned fonts draw it
382
+ * (`pajek-specimen-labels` `font-courier-bold` monospace, `font-helvetica-oblique` sans-serif and upright); any other
383
+ * name is the family as written. Pajek draws every label bold whatever the name says.
384
+ * @param raw - the parameter's value, or null
385
+ * @param put - receives the values
386
+ * @param at - the sites
387
+ */
388
+ function readFont(raw, put, at) {
389
+ if (raw === null || raw === "") {
390
+ return;
391
+ }
392
+ const ps = typeof raw === "string" ? postscriptFont(raw.trim()) : null;
393
+ if (ps === null) {
394
+ readText(raw, "labelFont", put, at);
395
+ return;
396
+ }
397
+ put("labelFont", ps.family);
398
+ }
399
+ /**
400
+ * A vertex label's angle `la` (manual p. 90), degrees counterclockwise, as a clockwise rotation: Pajek 6.02's SVG export
401
+ * turns the label by `rotate(-la)` (`pajek-specimen-labels`, `la-30` .. `la-270`). An angle of 360 or more turns the
402
+ * label away from the middle of the file's square, (0.5, 0.5) in its own coordinates, and then `la - 360` further
403
+ * (`la-360` at (0.4533, 0.3706) is drawn at -109.83, the direction from the middle; `la-400` at (0.5467, 0.3706) at
404
+ * -110.17, that direction, 70.17, and 40 more); without the vertex's place it is left unread.
405
+ * @param raw - the parameter's value, or null
406
+ * @param put - receives the value
407
+ * @param at - the sites
408
+ * @param place - the vertex's place in the file's coordinates, or null
409
+ */
410
+ function readLabelAngle(raw, put, at, place) {
411
+ let a = raw === null ? null : canonNumber(raw, at("labelRotation"));
412
+ if (a !== null && a >= 360) {
413
+ a = place === null ? null : (Math.atan2(0.5 - place[1], place[0] - 0.5) * 180) / Math.PI + a - 360;
414
+ }
415
+ if (a !== null) {
416
+ put("labelRotation", Number(((((360 - a) % 360) + 360) % 360).toPrecision(12)));
417
+ }
418
+ }
419
+ /**
420
+ * A vertex's width and height in points: the normal size times its `x_fact` and `y_fact`, each 1 when unset; a vertex
421
+ * that sets neither is left to the default beneath. The manual (p. 89) calls `s_size` "default size", but Pajek 6.02
422
+ * draws a vertex the same size whatever its `s_size` (`pajek-specimen-node-sizes-opacity`: `s_size` 0.5, 2 and 3 all
423
+ * drawn 36 across at `x_fact 1.8`), so it is not read. A man or a woman is the box of the figure Pajek draws for
424
+ * that size (`PAJEK_FIGURES`), set or not.
425
+ * @param get - the vertex's parameters
426
+ * @param put - receives the values
427
+ * @param at - the sites
428
+ * @param figure - a figure's width and height over its size, or undefined for another shape
429
+ */
430
+ function readSize(get, put, at, figure) {
431
+ for (const [key, property, k] of [
432
+ ["x_fact", "width", 0],
433
+ ["y_fact", "height", 1],
434
+ ]) {
435
+ const f = get(key);
436
+ if (f === null && figure === undefined) {
437
+ continue;
438
+ }
439
+ const factor = f === null ? 1 : canonNumber(f, at(property));
440
+ const over = figure?.[k] ?? 1;
441
+ put(property, factor === null ? null : Number((PAJEK_VERTEX_SIZE * factor * over).toPrecision(15)));
442
+ }
443
+ }
444
+ /**
445
+ * A text parameter (a PostScript font name).
446
+ * @param raw - the parameter's value, or null
447
+ * @param property - the property
448
+ * @param put - receives the value
449
+ * @param at - the sites
450
+ */
451
+ function readText(raw, property, put, at) {
452
+ if (raw !== null && raw !== "") {
453
+ put(property, canonText(raw, at(property)));
454
+ }
455
+ }
456
+ /** The `lphi` written for each side graphty puts a label on, and the side written for each Pajek has no angle for. */
457
+ const SIDE_ANGLES = new Map([
458
+ ["right", 0],
459
+ ["top-right", 90],
460
+ ["left", 180],
461
+ ["bottom-right", 285],
462
+ ]);
463
+ const NEAREST_SIDES = new Map([
464
+ ["top", "top-right"],
465
+ ["top-left", "top-right"],
466
+ ["bottom", "bottom-right"],
467
+ ["bottom-left", "bottom-right"],
468
+ ]);
469
+ /**
470
+ * A vertex's label place from Pajek's polar label parameters (manual p. 90): `lr` is the distance of the label from
471
+ * the vertex center, 0 centering it, and `lphi` its angle in degrees counterclockwise. Pajek 6.02's SVG export starts
472
+ * the text at that point, its baseline through it (`text-anchor` start at y = the point), so the label's left edge is
473
+ * at the point's x (`labelShiftX` 0.5) and its middle `PAJEK_BASELINE_TO_MIDDLE` of its size above the point's y
474
+ * (`pajek-specimen-labels` `lr-*`, `lphi-*`; every corpus label). A vertex that sets none of `lr`, `lphi` and `fos`
475
+ * is left to the default beneath, the same place at the default size.
476
+ * @param get - the vertex's parameters
477
+ * @param put - receives the values
478
+ * @param at - the sites
479
+ */
480
+ function readLabelPosition(get, put, at) {
481
+ const [lr, lphi, fos] = [get("lr"), get("lphi"), get("fos")];
482
+ if (lr === null && lphi === null && fos === null) {
483
+ return;
484
+ }
485
+ const radius = lr === null ? PAJEK_LABEL_RADIUS : canonNumber(lr, at("labelPosition"));
486
+ const angle = lphi === null ? PAJEK_LABEL_ANGLE : canonNumber(lphi, at("labelPosition"));
487
+ const size = fos === null ? PAJEK_LABEL_SIZE : canonNumber(fos, at("labelSize"));
488
+ if (radius === null || angle === null || size === null) {
489
+ return;
490
+ }
491
+ const [x, y] = labelOffset(radius, angle, size);
492
+ put("labelPosition", "center");
493
+ put("labelOffsetX", x);
494
+ put("labelOffsetY", y);
495
+ put("labelShiftX", radius === 0 ? 0 : 0.5);
496
+ }
497
+ /**
498
+ * Where Pajek's polar label parameters put a label, from the vertex center, y down: the middle of its left edge, or
499
+ * its middle when `lr` is 0, which centers it.
500
+ * @param radius - `lr`
501
+ * @param angle - `lphi`, degrees counterclockwise
502
+ * @param size - the label's size
503
+ * @returns the offset across and down
504
+ */
505
+ function labelOffset(radius, angle, size) {
506
+ if (radius === 0) {
507
+ return [0, 0];
508
+ }
509
+ const t = (angle * Math.PI) / 180;
510
+ const round = (v) => Number(v.toFixed(9)) + 0;
511
+ return [round(radius * Math.cos(t)), round(-radius * Math.sin(t) - PAJEK_BASELINE_TO_MIDDLE * size)];
135
512
  }
136
513
  /**
137
- * One line's style: its color, width and pattern.
514
+ * The label radius and angle Pajek uses when a vertex sets none: 20 and 285, below and to the right of the vertex.
515
+ * Measured in Pajek 6.02's own SVG export (`test/fidelity/oracles/pajek-football.svg`, `pajek-specimen-labels`
516
+ * `default`: every such label starts 20 from its vertex at 285 degrees); the size is the default label size.
517
+ */
518
+ const PAJEK_LABEL_RADIUS = 20;
519
+ const PAJEK_LABEL_ANGLE = 285;
520
+ const PAJEK_LABEL_SIZE = 15;
521
+ /**
522
+ * How far above its baseline a label's middle is, per unit of its size: half the ascent less the descent of Arial
523
+ * (Liberation Sans: 0.905 and 0.212), the face Pajek draws its labels in by default.
524
+ */
525
+ const PAJEK_BASELINE_TO_MIDDLE = 0.3465;
526
+ /**
527
+ * One line's style: its color, width and pattern. Pajek draws an edge (undirected) twice as wide as an arc of the
528
+ * same `w`.
138
529
  * @param get - the line's parameters
139
530
  * @param put - receives the values
140
531
  * @param at - the sites
532
+ * @param directed - whether the line is an arc
533
+ * @param labels - whether its label is drawn (`drawsLineLabels`)
534
+ * @param run - the line from its source's center to its target's, in drawn units, y down, or null when unplaced
535
+ * @param loop - for a loop on a placed node, receives its control points; null for any other line
141
536
  */
142
- function readLine(get, put, at) {
537
+ function readLine(get, put, at, directed, labels = true, run = null, loop = null) {
143
538
  readColor(get("c"), "color", "opacity", put, at);
144
- readNumber(get("w"), "width", put, at);
539
+ readNumber(get("w"), "width", (property, value) => {
540
+ put(property, typeof value === "number" && !directed ? value * EDGE_WIDTH_PER_W : value);
541
+ }, at);
145
542
  const p = get("p");
146
- if (p !== null) {
147
- put("lineStyle", canonEnum("lineStyle", p, "dvips", at("lineStyle")));
543
+ if (p === "Dots") {
544
+ put("lineStyle", pajekDash(get, directed));
545
+ }
546
+ else if (p === "Solid") {
547
+ put("lineStyle", "solid");
548
+ }
549
+ else if (p !== null) {
550
+ // Pajek knows Solid and Dots, case for case; any other pattern (`Dashed`, `dots`) draws a solid line
551
+ noteAt(at("lineStyle"), STYLE_ISSUE.UNKNOWN_VALUE, typeof p === "string" ? p : JSON.stringify(p));
552
+ put("lineStyle", "solid");
553
+ }
554
+ // an arrowhead is 6 x `s` long and 5 x `s` wide; `s` 1, Pajek's normal size, is 6 long (the pajek tool arrowhead)
555
+ readNumber(get("s"), "arrowSize", put, at);
556
+ readArrowPosition(get("ap"), put, at);
557
+ // a loop is drawn as the Bezier route of a line PAJEK_POINTS_PER_UNIT long to the right, its two ends on the node
558
+ const line = loop === null ? get : loopParam(get);
559
+ const controls = loop === null ? null : readLoop(line, put, loop);
560
+ if (labels) {
561
+ readText(get("l"), "label", put, at);
562
+ if (controls === null) {
563
+ readLineLabelPlace(get, put, at, run);
564
+ }
565
+ else {
566
+ readLineLabelPlace(line, put, at, [PAJEK_POINTS_PER_UNIT, 0], loopTop(controls));
567
+ }
568
+ }
569
+ if (loop === null) {
570
+ readBezier(get, put, run);
571
+ }
572
+ readColor(get("lc"), "labelColor", null, put, at);
573
+ readNumber(get("fos"), "labelSize", put, at);
574
+ readFont(get("font"), put, at);
575
+ }
576
+ /**
577
+ * The route parameters Pajek 6.02's SVG export draws a loop with where the line sets none (`pajek-specimen-edges-lines-p2`
578
+ * `loop` and `loop-arc`, `pajek-specimen-edge-labels` `on-loop`: a cubic from the node's center up and back, its control
579
+ * points 74.9 out at 70 and 110 degrees up from the right).
580
+ */
581
+ const LOOP_DEFAULTS = { a1: -70, k1: 0.3, a2: -70, k2: 0.3 };
582
+ /**
583
+ * A loop's route parameters: the line's own, Pajek's loop defaults for any it leaves out.
584
+ * @param get - the line's parameters
585
+ * @returns the parameters with the defaults
586
+ */
587
+ function loopParam(get) {
588
+ return (key) => get(key) ?? (key in LOOP_DEFAULTS ? LOOP_DEFAULTS[key] : null);
589
+ }
590
+ /**
591
+ * A loop's route (manual p. 90: "if arc is a loop (arc to itself) bezier loop will be drawn"), as Pajek 6.02's SVG
592
+ * export draws it: the Bezier route of a line PAJEK_POINTS_PER_UNIT long running right, both its ends on the node
593
+ * (`a1 -130 k1 0.6 a2 -130 k2 0.6`: control points 150 out at 130 and 50 degrees up from the right, measured on
594
+ * `pajek-specimen-edges-lines-p2` `loop-bezier`). Its bends are written once the nodes' sizes are known
595
+ * (`layLoops`). ponytail: measured in one Draw window (1200 x 900) and one vertex size; whether Pajek scales a loop
596
+ * with either was not measured.
597
+ * @param get - the line's parameters, with the loop defaults
598
+ * @param put - receives the values
599
+ * @param loop - receives the control points
600
+ * @returns the control points, or null when the line's parameters give none
601
+ */
602
+ function readLoop(get, put, loop) {
603
+ const run = [PAJEK_POINTS_PER_UNIT, 0];
604
+ const controls = bezierControls(get, run);
605
+ if (controls === null) {
606
+ return null;
607
+ }
608
+ const [[a1, l1], [a2, l2]] = controls;
609
+ const L = PAJEK_POINTS_PER_UNIT;
610
+ // along the line is right, left of it up: the second point is measured back from the line's far end, the node
611
+ const [c1, c2] = [
612
+ [a1 * L, -l1 * L],
613
+ [(a2 - 1) * L, -l2 * L],
614
+ ];
615
+ loop([c1, c2]);
616
+ put("curved", true);
617
+ put("bendCurve", "bezier");
618
+ // an arc's head is drawn where the loop comes back to its node's center, under the node
619
+ // (`pajek-specimen-edges-lines-p2` `loop-arc`, `s 1 a A`: no head shows)
620
+ put("targetArrow", "none");
621
+ return [c1, c2];
622
+ }
623
+ /**
624
+ * The way a loop runs at its top, where its label is drawn (`lp` 0.5): from its first control point to its second
625
+ * (`pajek-specimen-edge-labels` `on-loop`: 179.97). ponytail: a label elsewhere on the loop (`lp`) is turned as at
626
+ * its top.
627
+ * @param controls - the loop's control points
628
+ * @returns the direction, in degrees clockwise on screen
629
+ */
630
+ function loopTop(controls) {
631
+ const [c1, c2] = controls;
632
+ return (Math.atan2(c2[1] - c1[1], c2[0] - c1[0]) * 180) / Math.PI;
633
+ }
634
+ /**
635
+ * Writes each loop's control points as its bends, fractions of its node's half width and half height, y up, once the
636
+ * nodes are sized, and draws it round whatever the Draw window does to the other lines.
637
+ * @param snapshot - the graph
638
+ * @param loops - each loop's control points by edge
639
+ * @param node - the node values, sized
640
+ * @param edge - the edge values; changed in place
641
+ */
642
+ function layLoops(snapshot, loops, node, edge) {
643
+ const fraction = (x) => String(Math.round(x * 1e4) / 1e4 || 0);
644
+ for (const [e, controls] of loops) {
645
+ const v = snapshot.edgeSource(e);
646
+ const half = (property) => {
647
+ const size = node[property]?.[v];
648
+ return (typeof size === "number" && size > 0 ? size : PAJEK_VERTEX_SIZE) / 2;
649
+ };
650
+ const [hw, hh] = [half("width"), half("height")];
651
+ const column = (property) => (edge[property] ?? (edge[property] = new Array(snapshot.edgeCount).fill(null)));
652
+ column("bends")[e] = controls.map(([x, y]) => `${fraction(x / hw)},${fraction(-y / hh)}`).join(" ");
653
+ // Export Line Default / Straight Lines straightens every other line; a loop is still drawn round
654
+ // (`pajek-specimen-edges-lines-p4`)
655
+ column("curved")[e] = true;
656
+ column("bendCurve")[e] = "bezier";
657
+ }
658
+ }
659
+ /**
660
+ * Where Pajek 6.02's SVG export draws a line's label (`pajek-specimen-edge-labels`): its middle at `lp` from the
661
+ * terminal vertex, a fraction of the line up to 1 (0.5 by default, 0.2 near the target) and a distance beyond it
662
+ * (`lp 20` 20 from the target), moved by `lr` at `lphi` degrees counterclockwise (`lr 12 lphi 90` 12 above), its
663
+ * baseline through that point, and turned along the line and `la` degrees counterclockwise from it (`la 45` drawn
664
+ * rotate(-45) on a level line; `la 405` as `la 45`). graphty hangs a line's label on the line's middle, so the place is
665
+ * an offset from there, the words' middle above the baseline in the label's own turned frame.
666
+ * @param get - the line's parameters
667
+ * @param put - receives the values
668
+ * @param at - the sites
669
+ * @param run - the line, or null when unplaced
670
+ * @param direction - the line's direction at the label, in degrees clockwise on screen, where `run` does not give it
671
+ * (a loop)
672
+ */
673
+ function readLineLabelPlace(get, put, at, run, direction) {
674
+ const length = run === null ? 0 : Math.hypot(run[0], run[1]);
675
+ if (run === null || length === 0) {
676
+ return;
677
+ }
678
+ const n = (key, fallback, property) => {
679
+ const v = get(key);
680
+ return v === null ? fallback : canonNumber(v, at(property));
681
+ };
682
+ const [lp, lr, lphi, la] = [
683
+ n("lp", 0.5, "labelOffsetX"),
684
+ n("lr", 0, "labelOffsetX"),
685
+ n("lphi", 0, "labelOffsetX"),
686
+ n("la", 0, "labelRotation"),
687
+ ];
688
+ const size = n("fos", PAJEK_LABEL_SIZE, "labelSize");
689
+ if (lp === null || lr === null || lphi === null || la === null || size === null) {
690
+ return;
691
+ }
692
+ // from the line's middle to the point lp from its target, then out by lr at lphi
693
+ const along = 0.5 - (lp <= 1 ? lp : lp / length);
694
+ const t = (lphi * Math.PI) / 180;
695
+ const round = (v) => Number(v.toFixed(9)) + 0;
696
+ const turn = (((direction ?? lineDirection(get, run, along + 0.5)) - la) % 360) + 360;
697
+ // the baseline runs through the point; the words' middle is above it in the label's own turned frame
698
+ const up = (turn * Math.PI) / 180;
699
+ const rise = PAJEK_BASELINE_TO_MIDDLE * size;
700
+ put("labelPosition", "center");
701
+ put("labelOffsetX", round(along * run[0] + lr * Math.cos(t) + rise * Math.sin(up)));
702
+ put("labelOffsetY", round(along * run[1] - lr * Math.sin(t) - rise * Math.cos(up)));
703
+ put("labelRotation", round(turn % 360));
704
+ }
705
+ /**
706
+ * A line's Bezier route (manual p. 90: `a1`, `k1` at its source, `a2`, `k2` at its target), as Pajek 6.02's SVG export
707
+ * draws it (`pajek-specimen-edges-lines-p2`, `pajek-specimen-edge-labels`): one cubic Bezier curve whose first control
708
+ * point is `k1` / 2 of the line's length from the source, turned `a1` degrees clockwise on screen from the line, and
709
+ * whose second is `k2` / 2 of it back from the target, turned `a2` degrees counterclockwise (`a1 40 k1 1.5 a2 -40 k2
710
+ * 1.5` an S, `a2 40` a bow). A negative `k1` is one of Pajek's oval, circular arc or double routes, which its SVG export
711
+ * draws straight. A loop is `readLoop`'s. ponytail: a line that sets only some of the four reads the
712
+ * others as 0 and 1; Pajek's values for them were not measured.
713
+ * @param get - the line's parameters
714
+ * @param put - receives the values
715
+ * @param run - the line, or null when unplaced
716
+ */
717
+ function readBezier(get, put, run) {
718
+ const controls = bezierControls(get, run);
719
+ if (controls === null) {
720
+ return;
721
+ }
722
+ const fraction = (x) => String(Math.round(x * 1e4) / 1e4 || 0);
723
+ put("curved", true);
724
+ put("bendCurve", "bezier");
725
+ put("bends", controls.map(([along, across]) => `${fraction(along)},${fraction(across)}`).join(" "));
726
+ }
727
+ /**
728
+ * Where Pajek 6.02's SVG export ends an arc's Bezier route (`readBezier`): at its arrowhead's back, not at its target's
729
+ * center. It places the arrowhead as on a straight arc, its tip 1.5 short of where the straight line meets the
730
+ * target's outline, turns it `-a2` degrees about that point, and runs the curve from the source's center to the
731
+ * arrowhead's back, its control points measured on that shorter line (`pajek-specimen-edges-lines-p2`
732
+ * `route-bezier-opposite-arc`: the arrowhead's back at (347.02, 124.32), 6.5 back from the outline at (352, 128.5),
733
+ * turned 40 degrees; `route-bezier-same-arc` at (571.02, 132.68), turned -40). graphty draws the route to the target's
734
+ * center and stops it at the outline, so the curve's control points are written in the frame of that line.
735
+ * ponytail: the outline is the ellipse of the vertex's width and height, as the file sizes it (before the Draw
736
+ * window's Size of Vertices or vectors), whatever its shape.
737
+ * @param get - the line's parameters
738
+ * @param put - receives the values
739
+ * @param run - the line from its source's center to its target's, in drawn units, y down
740
+ * @param target - the target vertex's width and height
741
+ */
742
+ function readArcEnd(get, put, run, target) {
743
+ const ap = numberOrNull(get("ap")) ?? 0;
744
+ const length = Math.hypot(run[0], run[1]);
745
+ if (ap !== 0 || length === 0 || bezierControls(get, run) === null) {
746
+ return;
747
+ }
748
+ const [ux, uy] = [run[0] / length, run[1] / length];
749
+ // the straight line meets the outline r from the target's center; the arrowhead's back is 1.5 + 5 s before it
750
+ const r = 1 / Math.hypot(ux / (target[0] / 2), uy / (target[1] / 2));
751
+ const back = 1.5 + 5 * (numberOrNull(get("s")) ?? 1);
752
+ const turn = (-(numberOrNull(get("a2")) ?? 0) * Math.PI) / 180;
753
+ const [c, s] = [Math.cos(turn), Math.sin(turn)];
754
+ // the arrowhead's back, from the source's center
755
+ const end = [run[0] - r * ux - back * (ux * c - uy * s), run[1] - r * uy - back * (ux * s + uy * c)];
756
+ const controls = bezierControls(get, end);
757
+ if (controls === null) {
758
+ return;
759
+ }
760
+ // each control point on screen from the source's center, then along and to the left of the line to the target
761
+ const L2 = length * length;
762
+ const fraction = (x) => String(Math.round(x * 1e4) / 1e4 || 0);
763
+ const bends = controls.map(([along, left]) => {
764
+ const [x, y] = [along * end[0] + left * end[1], along * end[1] - left * end[0]];
765
+ return `${fraction((x * run[0] + y * run[1]) / L2)},${fraction((x * run[1] - y * run[0]) / L2)}`;
766
+ });
767
+ put("bends", bends.join(" "));
768
+ }
769
+ /**
770
+ * A line's two Bezier control points (`readBezier`), each `[along, across]` as fractions of the line from its source:
771
+ * along it, and to its left on screen.
772
+ * @param get - the line's parameters
773
+ * @param run - the line, or null when unplaced
774
+ * @returns the points, or null for a line Pajek draws straight or a loop
775
+ */
776
+ function bezierControls(get, run) {
777
+ const [a1, k1, a2, k2] = ["a1", "k1", "a2", "k2"].map((key) => numberOrNull(get(key)));
778
+ if ((a1 === null && k1 === null && a2 === null && k2 === null) || run === null || (run[0] === 0 && run[1] === 0)) {
779
+ return null;
780
+ }
781
+ const [s, t] = [k1 ?? 1, k2 ?? 1];
782
+ if (s < 0 || t < 0) {
783
+ return null;
784
+ }
785
+ const rad = Math.PI / 180;
786
+ const [u, v] = [(a1 ?? 0) * rad, (a2 ?? 0) * rad];
787
+ return [
788
+ [(s / 2) * Math.cos(u), (-s / 2) * Math.sin(u)],
789
+ [1 - (t / 2) * Math.cos(v), (-t / 2) * Math.sin(v)],
790
+ ];
791
+ }
792
+ /**
793
+ * A line's direction on screen, in degrees clockwise, where its label is drawn: along a straight line, or along its
794
+ * Bezier curve (`bezierControls`) at the label's place, `along` of the way from the source.
795
+ * @param get - the line's parameters
796
+ * @param run - the line
797
+ * @param along - the label's place, 0 at the source and 1 at the target
798
+ * @returns the direction
799
+ */
800
+ function lineDirection(get, run, along) {
801
+ const controls = bezierControls(get, run);
802
+ let [dx, dy] = run;
803
+ if (controls !== null) {
804
+ // the cubic's tangent at `along`, in the line's own frame (along, left), then on screen
805
+ const t = Math.min(1, Math.max(0, along));
806
+ const p = [[0, 0], ...controls, [1, 0]];
807
+ const d = (k) => 3 * (1 - t) ** 2 * (p[1][k] - p[0][k]) +
808
+ 6 * (1 - t) * t * (p[2][k] - p[1][k]) +
809
+ 3 * t ** 2 * (p[3][k] - p[2][k]);
810
+ const [a, l] = [d(0), d(1)];
811
+ // left of (dx, dy) on screen, y down, is (dy, -dx)
812
+ [dx, dy] = [a * run[0] + l * run[1], a * run[1] - l * run[0]];
813
+ }
814
+ return (Math.atan2(dy, dx) * 180) / Math.PI;
815
+ }
816
+ /**
817
+ * What a line's value draws (manual 5.3 p. 90): a line of value 0 is not drawn, and a negative one is drawn as Dots
818
+ * unless the line sets a pattern.
819
+ * @param value - the line's value, or null
820
+ * @param get - the line's parameters
821
+ * @param put - receives the values
822
+ * @param directed - whether the line is an arc
823
+ */
824
+ function readLineValue(value, get, put, directed = true) {
825
+ if (value === 0) {
826
+ put("visible", false);
827
+ }
828
+ else if (value !== null && value < 0 && get("p") === null) {
829
+ // drawn as Dots are (`pajek-specimen-edges-lines` `value-negative`)
830
+ put("lineStyle", pajekDash(get, directed));
831
+ }
832
+ }
833
+ /** The dash and the gap of Pajek 6.02's Dots, in px whatever the line's width (`stroke-dasharray:5`). */
834
+ const PAJEK_DASH = 5;
835
+ /**
836
+ * How a line drawn as Pajek's Dots looks: Pajek 6.02's SVG export draws it `stroke-dasharray:5`, dashes and gaps 5 px
837
+ * long whatever the line's width, so a line 10/3 px wide or wider, its dashes no longer than one and a half widths,
838
+ * shows dots and a thinner one dashes (`pajek-specimen-edges-lines` `p-dots` at 1.5: dashes; `pajek-synth-lines`
839
+ * arc `12 13` at w 5 and edge `1 8` at w 3, drawn 6 wide: dots).
840
+ * @param get - the line's parameters
841
+ * @param directed - whether the line is an arc, drawn `w` wide (an edge twice `w`)
842
+ * @returns the line style
843
+ */
844
+ function pajekDash(get, directed) {
845
+ const w = numberOrNull(get("w"));
846
+ // without a `w`, Pajek's arc is 1 wide and its edge 2
847
+ const width = (w ?? 1) * (directed ? 1 : EDGE_WIDTH_PER_W);
848
+ return PAJEK_DASH <= 1.5 * Math.max(1, width) ? "dotted" : "dashed";
849
+ }
850
+ /**
851
+ * A line's hooks `h1` and `h2` (manual p. 90): the points of its source's and its target's outline it runs between,
852
+ * numbered by Pajek's shipped SHAPES.CFG for the vertex's shape. An ellipse's hook k is at k degrees counterclockwise
853
+ * from the right (CIRC `10 1`), a box's runs round its border in 400 steps from the middle of its right side,
854
+ * counterclockwise (CART), and a cross, which Pajek draws as an ellipse, has an ellipse's; `pajek-specimen-edges-lines-p2`:
855
+ * `h1 90 h2 270` runs from the top of the source to the bottom of the target, `h1 1 h2 1` ends on the far side of the
856
+ * target, `h1 1` on a box leaves at its right side. 0 (the center) and -1 (the nearest hook) are where graphty runs a
857
+ * line anyway. ponytail: the hooks of the other shapes (a diamond's 360 polar radii, a triangle's, a figure's) are
858
+ * not read; Pajek's box hook 100 was measured 0.22 of the half width left of the top's middle, where SHAPES.CFG puts
859
+ * it.
860
+ * @param get - the line's parameters
861
+ * @param put - receives the values
862
+ * @param source - the source vertex's shape keyword, or null
863
+ * @param target - the target vertex's shape keyword, or null
864
+ */
865
+ function readHooks(get, put, source, target) {
866
+ for (const [key, property, shape] of [
867
+ ["h1", "sourcePort", source],
868
+ ["h2", "targetPort", target],
869
+ ]) {
870
+ const hook = numberOrNull(get(key));
871
+ const port = hook === null ? null : hookPort(shape, hook);
872
+ if (port !== null) {
873
+ const round = (v) => String(Number(v.toFixed(4)) + 0);
874
+ put(property, `${round(port[0])},${round(port[1])}`);
875
+ }
876
+ }
877
+ }
878
+ /**
879
+ * One hook's point on its vertex (`readHooks`), as fractions of the half width and height, y up.
880
+ * @param shape - the vertex's shape keyword, null for Pajek's default ellipse
881
+ * @param hook - the hook's number
882
+ * @returns the point, or null where Pajek's hook is not read
883
+ */
884
+ function hookPort(shape, hook) {
885
+ if (!Number.isInteger(hook) || hook < 1) {
886
+ return null;
887
+ }
888
+ const keyword = typeof shape === "string" ? shape.toLowerCase() : "ellipse";
889
+ // Pajek 6.02 draws a cross as an ellipse, with an ellipse's hooks (`h-cross-1-3`: hook 3 at 3 degrees)
890
+ if (keyword === "ellipse" || keyword === "cross") {
891
+ const a = (hook * Math.PI) / 180;
892
+ return [Math.cos(a), Math.sin(a)];
893
+ }
894
+ if (keyword !== "box" || hook > 400) {
895
+ return null;
896
+ }
897
+ // 0.02 of the half size a step: up the right side's top half, across the top, down the left, across the
898
+ // bottom and up the right side's bottom half
899
+ const d = hook * 0.02;
900
+ if (hook <= 50) {
901
+ return [1, d];
902
+ }
903
+ if (hook <= 150) {
904
+ return [2 - d, 1];
905
+ }
906
+ if (hook <= 250) {
907
+ return [-1, 4 - d];
908
+ }
909
+ return hook <= 350 ? [d - 6, -1] : [1, d - 8];
910
+ }
911
+ /**
912
+ * A cell's number: a number as is, a numeric text parsed, anything else null.
913
+ * @param raw - the cell
914
+ * @returns the number, or null
915
+ */
916
+ function numberOrNull(raw) {
917
+ if (typeof raw === "string" && raw.trim() !== "") {
918
+ raw = Number(raw);
919
+ }
920
+ return typeof raw === "number" && Number.isFinite(raw) ? raw : null;
921
+ }
922
+ /**
923
+ * Where a line's arrowhead sits, Pajek's `ap` (manual p. 90): a fraction of the line from its end up to 1 (0.5 is the
924
+ * middle); a value above 1 is a distance from the end, which the vocabulary does not hold, so it is noted and not read.
925
+ * @param raw - the parameter's value, or null
926
+ * @param put - receives the value
927
+ * @param at - the sites
928
+ */
929
+ function readArrowPosition(raw, put, at) {
930
+ if (raw === null) {
931
+ return;
932
+ }
933
+ const ap = canonNumber(raw, at("arrowPosition"));
934
+ if (ap !== null && ap > 1) {
935
+ noteAt(at("arrowPosition"), STYLE_ISSUE.NOT_CARRIED, `ap ${String(ap)}`);
936
+ return;
937
+ }
938
+ // 0 is Pajek's own place for the arrow, at the line's end, which a line restates after one that moved it
939
+ if (ap !== 0) {
940
+ put("arrowPosition", ap);
148
941
  }
149
942
  }
150
943
  /**
@@ -154,8 +947,18 @@ function readLine(get, put, at) {
154
947
  * @returns the getter
155
948
  */
156
949
  function cells(table, i) {
157
- return (key) => (table.has(key) ? plainCell(table.value(key, i)) : null);
950
+ return (key) => {
951
+ const v = table.has(key) ? plainCell(table.value(key, i)) : null;
952
+ // a color written as numbers (`c 0.700 0.700 0.700`) is no color to Pajek 6.02: the line keeps the color it
953
+ // carries from the line before, or Pajek's default (`pajek-1crn`, `pajek-specimen-edges-lines`
954
+ // `c-three-fractions`). ponytail: measured on lines; vertex colors are read the same way
955
+ return COLOR_PARAMS.has(key) && typeof v === "string" && NUMERIC_COLOR.test(v) ? null : v;
956
+ };
158
957
  }
958
+ /** The parameters that hold a color. */
959
+ const COLOR_PARAMS = new Set(["ic", "bc", "lc", "c"]);
960
+ /** A color written as numbers rather than a name or an RGB / CMYK form. */
961
+ const NUMERIC_COLOR = /^[\d.]+(?: [\d.]+)*$/;
159
962
  /**
160
963
  * Whether each edge is an arc (directed).
161
964
  * @param snapshot - the graph
@@ -181,37 +984,89 @@ function styleColumns(table, keys) {
181
984
  return keys.filter((k) => table.has(k));
182
985
  }
183
986
  /**
184
- * The styles of a Pajek file, read the way Pajek draws them, with Pajek's stated defaults beneath: a labeled ellipse
185
- * with a black border and a black centered label, black solid lines, and an arrow at the target of every arc. A file graphty wrote gives back its `graphty.styles` block.
987
+ * The styles of a Pajek file, read the way Pajek draws them, with Pajek's own defaults beneath: a labeled #ffd9bc
988
+ * ellipse with a #660000 border, teal edges, and grey arcs with an arrow at the target. A file graphty wrote gives back its `graphty.styles` block.
186
989
  * @param snapshot - the graph the import built
187
990
  * @param context - the work budget and the block text the import kept
188
991
  * @returns the styles
189
992
  */
190
993
  export function pajekStyles(snapshot, context) {
191
994
  const notes = new StyleNotes();
995
+ const { block, draw, voided } = keptOf(context.kept);
996
+ const labels = drawsLineLabels(draw);
997
+ const place = places(snapshot);
998
+ // Pajek stretches the file's 0..1 to its Draw window one axis at a time, 500 x 500 without one
999
+ const window = draw ?? { width: PAJEK_POINTS_PER_UNIT, height: PAJEK_POINTS_PER_UNIT };
1000
+ const loops = new Map();
1001
+ const runOf = (e) => {
1002
+ const [s, t] = [place(snapshot.edgeSource(e)), place(snapshot.edgeTarget(e))];
1003
+ return s === null || t === null ? null : [(t[0] - s[0]) * window.width, (t[1] - s[1]) * window.height];
1004
+ };
192
1005
  const read = (target) => {
193
1006
  const table = target === "node" ? snapshot.nodes : snapshot.edges;
194
1007
  const n = target === "node" ? snapshot.nodeCount : snapshot.edgeCount;
195
1008
  const out = valueColumns(n);
1009
+ const carry = carriedParams(target === "node" ? CARRIED.node : CARRIED_LINE, target === "node");
196
1010
  for (let i = 0; i < n; i++) {
197
1011
  context.budget.spend(target, 1);
198
1012
  const at = (property) => ({ notes, target, property, element: i, budget: context.budget });
199
- (target === "node" ? readVertex : readLine)(cells(table, i), (property, value) => {
1013
+ const put = (property, value) => {
200
1014
  out.put(i, property, value);
201
- }, at);
1015
+ };
1016
+ const own = cells(table, i);
1017
+ const get = target === "node" && voided.has(i) ? voidedParams(own, keywords[i - 1] ?? null) : carry(own);
1018
+ if (target === "node") {
1019
+ readVertex(get, put, at, place(i));
1020
+ keywords[i] = get(SHAPE_COLUMN);
1021
+ }
1022
+ else {
1023
+ readEdge(i, get, put, at);
1024
+ }
202
1025
  }
203
1026
  return out.values;
204
1027
  };
1028
+ const readEdge = (i, get, put, at) => {
1029
+ // a loop on a placed node: an unplaced one is laid out by graphty, which draws its own loop, and a
1030
+ // file graphty wrote keeps its routes in its block
1031
+ const run = runOf(i);
1032
+ const loop = run !== null && block === null && snapshot.edgeSource(i) === snapshot.edgeTarget(i)
1033
+ ? (controls) => {
1034
+ loops.set(i, controls);
1035
+ }
1036
+ : null;
1037
+ readLine(get, put, at, directed[i], labels, run, loop);
1038
+ if (directed[i] && loop === null && run !== null) {
1039
+ readArcEnd(get, put, run, targetSize(snapshot.edgeTarget(i)));
1040
+ }
1041
+ readLineValue(lineValue(i), get, put, directed[i]);
1042
+ readHooks(get, put, keywords[snapshot.edgeSource(i)], keywords[snapshot.edgeTarget(i)]);
1043
+ };
1044
+ const directed = directedEdges(snapshot);
1045
+ const keywords = [];
1046
+ const weights = explicitWeights(snapshot);
1047
+ // the line's value: its weight, or the `value` column when the import kept the value as an attribute
1048
+ const lineValue = (e) => weights.isExplicit(e) ? weights.value(e) : numberOrNull(cells(snapshot.edges, e)(VALUE_COLUMN));
205
1049
  const node = read("node");
1050
+ // a vertex's width and height as the file draws it, for where an arc's arrowhead meets it
1051
+ const targetSize = (v) => {
1052
+ const size = (property) => {
1053
+ const s = node[property]?.[v];
1054
+ return typeof s === "number" && s > 0 ? s : PAJEK_VERTEX_SIZE;
1055
+ };
1056
+ return [size("width"), size("height")];
1057
+ };
206
1058
  const edge = read("edge");
207
- const block = typeof context.kept === "string" ? context.kept : null;
1059
+ if (draw !== null) {
1060
+ drawVertices(draw, snapshot, node);
1061
+ drawLines(draw, snapshot, node, edge);
1062
+ }
1063
+ layLoops(snapshot, loops, node, edge);
208
1064
  if (block !== null) {
209
- exactFromBlock(snapshot, block, { node, edge });
1065
+ exactFromBlock(snapshot, block, { node, edge }, labels);
210
1066
  }
211
- // Pajek's default that is a rule: an arc has an arrow at its target, an edge none
1067
+ // Pajek's defaults that are a rule: an arc has an arrow at its target and is drawn grey and thinner, an edge not
212
1068
  const rules = [];
213
1069
  const columns = new Map();
214
- const directed = directedEdges(snapshot);
215
1070
  if (directed.some(Boolean)) {
216
1071
  columns.set(DIRECTED_KEY, directed.map((d) => (d ? true : null)));
217
1072
  rules.push({
@@ -220,14 +1075,14 @@ export function pajekStyles(snapshot, context) {
220
1075
  role: "group",
221
1076
  origin: "tool",
222
1077
  where: { has: { style: DIRECTED_KEY } },
223
- set: { targetArrow: "triangle" },
1078
+ set: { targetArrow: "triangle", color: ARC_DEFAULTS.color, width: ARC_DEFAULTS.width },
224
1079
  });
225
1080
  }
226
1081
  return {
227
1082
  canonical: true,
228
1083
  dialect: "dvips",
229
1084
  tool: "pajek",
230
- units: "relative",
1085
+ units: "px",
231
1086
  node: { values: node },
232
1087
  edge: { values: edge, rules, columns },
233
1088
  notes: notes.list(),
@@ -238,6 +1093,60 @@ export function pajekStyles(snapshot, context) {
238
1093
  },
239
1094
  };
240
1095
  }
1096
+ /**
1097
+ * Each vertex's place in the file's own coordinates, as the position column holds them.
1098
+ * @param snapshot - the graph
1099
+ * @returns a getter of a vertex's place, null when it has none
1100
+ */
1101
+ function places(snapshot) {
1102
+ const col = snapshot.nodes.byRole("position");
1103
+ return (i) => {
1104
+ const v = col === null || col === undefined ? null : col.value(i);
1105
+ if (v === null || typeof v !== "object" || !("length" in v)) {
1106
+ return null;
1107
+ }
1108
+ const [x, y] = v;
1109
+ return typeof x === "number" && typeof y === "number" ? [x, y] : null;
1110
+ };
1111
+ }
1112
+ /**
1113
+ * What the import kept for the styles: the `graphty.styles` block, the Draw window of the `pajekDraw` option, and the
1114
+ * vertices whose line Pajek draws with none of its parameters.
1115
+ * @param kept - the kept value: the block's text, or `{ block, pajekDraw, voided }`
1116
+ * @returns the block and the draw settings, each null when absent, and the voided vertices
1117
+ */
1118
+ function keptOf(kept) {
1119
+ if (typeof kept === "string") {
1120
+ return { block: kept, draw: null, voided: new Set() };
1121
+ }
1122
+ if (typeof kept === "object" && kept !== null) {
1123
+ const { block, pajekDraw, voided } = kept;
1124
+ return {
1125
+ block: typeof block === "string" ? block : null,
1126
+ draw: pajekDraw ?? null,
1127
+ voided: new Set(voided ?? []),
1128
+ };
1129
+ }
1130
+ return { block: null, draw: null, voided: new Set() };
1131
+ }
1132
+ /**
1133
+ * The parameters Pajek 6.02 draws a voided vertex line with (`VOIDING_KEYS` in the importer): its label, and none of
1134
+ * its own parameters, so the vertex is Pajek's default size and colors, in the shape of the vertex line before it
1135
+ * (`pajek-specimen-node-sizes-opacity` `s-size-no-shape`, after a box: a box 20 across in #ffd9bc). ponytail: probes
1136
+ * showed the shape is not always the line before's (after `box ic Green` a voided line drew an ellipse in one file and
1137
+ * the triangle of two lines before in another); the rule Pajek follows was not found.
1138
+ * @param own - the line's own parameters
1139
+ * @param before - the shape keyword of the vertex line before it, or null
1140
+ * @returns the getter
1141
+ */
1142
+ function voidedParams(own, before) {
1143
+ return (key) => {
1144
+ if (key === LABEL_COLUMN) {
1145
+ return own(key);
1146
+ }
1147
+ return key === SHAPE_COLUMN ? before : null;
1148
+ };
1149
+ }
241
1150
  /** Pajek's shape keywords for graphty's shapes; a shape not listed is written as its nearest. */
242
1151
  const SHAPES = new Map([
243
1152
  ["ellipse", "ellipse"],
@@ -296,12 +1205,57 @@ function shapeKeyword(get, approximate) {
296
1205
  if (keyword !== undefined) {
297
1206
  return keyword;
298
1207
  }
1208
+ if (shape === "polygon" && diamondQ(get) !== null) {
1209
+ return "diamond";
1210
+ }
299
1211
  approximate("shape", shape);
1212
+ const points = get("shapePoints");
1213
+ if (shape === "polygon" && points !== null) {
1214
+ approximate("shapePoints", points);
1215
+ }
300
1216
  return NEAREST_SHAPES.get(shape) ?? "ellipse";
301
1217
  }
302
1218
  /**
303
- * A vertex's parameters from its values, leaving out what Pajek draws by default: an ellipse with a black border 1
304
- * wide and a black label.
1219
+ * The `q` of a polygon that is Pajek's unturned diamond (`readOutline`), or null for any other.
1220
+ * @param get - the vertex's values
1221
+ * @returns the diamond's `q`, or null
1222
+ */
1223
+ function diamondQ(get) {
1224
+ const points = get("shapePoints");
1225
+ const corners = typeof points === "string"
1226
+ ? points
1227
+ .trim()
1228
+ .split(/\s+/)
1229
+ .map((p) => p.split(",").map(Number))
1230
+ : [];
1231
+ if (corners.length !== 6) {
1232
+ return null;
1233
+ }
1234
+ const q = corners[2][0];
1235
+ const want = [
1236
+ [-1, 0],
1237
+ [-q, 1],
1238
+ [q, 1],
1239
+ [1, 0],
1240
+ [q, -1],
1241
+ [-q, -1],
1242
+ ];
1243
+ return want.every(([x, y], k) => corners[k][0] === x && corners[k][1] === y) ? q : null;
1244
+ }
1245
+ /**
1246
+ * What Pajek draws by default for a property (`styles/defaults.ts`), which the writer leaves out.
1247
+ * @param target - nodes or edges
1248
+ * @param property - the property
1249
+ * @returns the default, or undefined
1250
+ */
1251
+ function pajekDefault(target, property) {
1252
+ const values = toolDefaults("pajek")?.[target];
1253
+ return values?.[property]?.value;
1254
+ }
1255
+ /**
1256
+ * A vertex's parameters from its values, leaving out the ellipse and the black border 1 wide Pajek draws by default;
1257
+ * the inverse of `readVertex`: `x_fact` and `y_fact` are the width and height over the normal size, the other lengths
1258
+ * points as they are.
305
1259
  * @param get - the vertex's values
306
1260
  * @param approximate - records approximations
307
1261
  * @returns the parameters, the shape keyword under `shape`
@@ -313,43 +1267,139 @@ function vertexParams(get, approximate) {
313
1267
  if (keyword !== "ellipse") {
314
1268
  out.set(SHAPE_COLUMN, keyword);
315
1269
  }
1270
+ const q = diamondQ(get);
1271
+ if (q !== null && q !== PAJEK_DIAMOND_Q) {
1272
+ out.set("q", q);
1273
+ }
1274
+ vertexColorParams(get, out);
1275
+ vertexSizeParams(get, out);
1276
+ const bw = get("borderWidth");
1277
+ if (typeof bw === "number" && bw !== pajekDefault("node", "borderWidth")) {
1278
+ out.set("bw", bw);
1279
+ }
1280
+ fontParam(get, out, pajekDefault("node", "labelFont"));
1281
+ labelPositionParams(get, out, approximate);
1282
+ return out;
1283
+ }
1284
+ /**
1285
+ * A vertex's colors as parameters (`ic`, `bc`, `lc`), leaving out Pajek's defaults.
1286
+ * @param get - the vertex's values
1287
+ * @param out - receives the parameters
1288
+ */
1289
+ function vertexColorParams(get, out) {
316
1290
  const colors = [
317
1291
  ["fill", "ic"],
318
1292
  ["borderColor", "bc"],
319
1293
  ["labelColor", "lc"],
320
1294
  ];
321
- const numbers = [
322
- ["width", "x_fact"],
323
- ["height", "y_fact"],
324
- ["labelSize", "fos"],
325
- ];
326
1295
  for (const [property, key] of colors) {
327
1296
  const v = get(property);
328
- if (typeof v === "string" && (property === "fill" || v !== "#000000")) {
1297
+ if (typeof v === "string" && v !== pajekDefault("node", property)) {
329
1298
  out.set(key, pajekColorText(v));
330
1299
  }
331
1300
  }
332
- for (const [property, key] of numbers) {
1301
+ }
1302
+ /**
1303
+ * A vertex's sizes as parameters (`x_fact`, `y_fact`, `fos`), leaving out Pajek's defaults.
1304
+ * @param get - the vertex's values
1305
+ * @param out - receives the parameters
1306
+ */
1307
+ function vertexSizeParams(get, out) {
1308
+ const numbers = [
1309
+ ["width", "x_fact", PAJEK_VERTEX_SIZE],
1310
+ ["height", "y_fact", PAJEK_VERTEX_SIZE],
1311
+ ["labelSize", "fos", 1],
1312
+ ];
1313
+ // a man's or a woman's box is the figure's, which reaches past the size its x_fact and y_fact give (readSize)
1314
+ const figure = PAJEK_FIGURES.get(String(get("shape")));
1315
+ for (const [property, key, per] of numbers) {
333
1316
  const v = get(property);
334
- if (typeof v === "number") {
335
- out.set(key, v);
1317
+ let over = 1;
1318
+ if (figure !== undefined && key !== "fos") {
1319
+ over = figure[key === "x_fact" ? 0 : 1];
1320
+ }
1321
+ if (typeof v === "number" && (over !== 1 || v !== pajekDefault("node", property))) {
1322
+ out.set(key, Number((v / (per * over)).toPrecision(15)));
336
1323
  }
337
1324
  }
338
- const bw = get("borderWidth");
339
- if (typeof bw === "number") {
340
- const written = Number((bw * VERTEX_SIZE).toPrecision(15));
341
- if (written === 1) {
342
- out.delete("bw");
1325
+ }
1326
+ /**
1327
+ * A label's `font`, the inverse of `readFont`: a PostScript family with a generic one after it is written by its
1328
+ * PostScript name (`Courier, monospace` as `Courier`), any other family as it is; Pajek draws every label bold and
1329
+ * upright, so neither the weight nor the slant is written.
1330
+ * @param get - the element's values
1331
+ * @param out - the parameters, changed in place
1332
+ * @param skip - the font left out, Pajek's default, or undefined
1333
+ */
1334
+ function fontParam(get, out, skip) {
1335
+ const font = get("labelFont");
1336
+ const name = typeof font === "string" && font !== "" ? graphvizFontName(font, false, false) : null;
1337
+ if (name !== null && name !== skip) {
1338
+ out.set("font", name);
1339
+ }
1340
+ }
1341
+ /**
1342
+ * A label position as Pajek's polar label parameters, leaving out the default (20 from the center at 285 degrees): a
1343
+ * label centered with its left edge's middle offset from the center is `lr` and `lphi` (the inverse of
1344
+ * `readLabelPosition`), one centered on the vertex `lr 0`, and a side its angle `lphi`; a side Pajek cannot put a
1345
+ * label on is written as the nearest it can, and noted.
1346
+ * @param get - the vertex's values
1347
+ * @param out - the parameters, changed in place
1348
+ * @param approximate - records approximations
1349
+ */
1350
+ function labelPositionParams(get, out, approximate) {
1351
+ const position = get("labelPosition");
1352
+ if (typeof position !== "string") {
1353
+ return;
1354
+ }
1355
+ if (position === "center") {
1356
+ const polar = polarOf(get);
1357
+ if (polar === null) {
1358
+ out.set("lr", 0);
343
1359
  }
344
- else {
345
- out.set("bw", written);
1360
+ else if (polar[0] !== PAJEK_LABEL_RADIUS || polar[1] !== PAJEK_LABEL_ANGLE) {
1361
+ out.set("lr", polar[0]);
1362
+ out.set("lphi", polar[1]);
346
1363
  }
1364
+ return;
1365
+ }
1366
+ const nearest = NEAREST_SIDES.get(position);
1367
+ if (nearest !== undefined) {
1368
+ approximate("labelPosition", position);
1369
+ }
1370
+ const angle = SIDE_ANGLES.get(nearest ?? position);
1371
+ if (angle !== undefined && angle !== PAJEK_LABEL_ANGLE) {
1372
+ out.set("lphi", angle);
347
1373
  }
348
- return out;
349
1374
  }
350
1375
  /**
351
- * A line's parameters from its values, leaving out Pajek's black solid line. Arrows are Pajek's own: an arc has one
352
- * at its target and an edge none, so any other arrow is noted.
1376
+ * The `lr` and `lphi` that put a centered label where its offsets say (`labelOffset`, inverted), 6 places each.
1377
+ * @param get - the vertex's values
1378
+ * @returns `[lr, lphi]`, or null for a label on the vertex's center (no offset, no shift)
1379
+ */
1380
+ function polarOf(get) {
1381
+ const [x, y, shift] = [get("labelOffsetX"), get("labelOffsetY"), get("labelShiftX")];
1382
+ if (typeof x !== "number" || typeof y !== "number" || shift !== 0.5) {
1383
+ return null;
1384
+ }
1385
+ const size = get("labelSize");
1386
+ const up = y + PAJEK_BASELINE_TO_MIDDLE * (typeof size === "number" ? size : PAJEK_LABEL_SIZE);
1387
+ const round = (v) => Number(v.toFixed(6)) + 0;
1388
+ const lr = round(Math.hypot(x, up));
1389
+ return lr === 0 ? null : [lr, round(((((Math.atan2(-up, x) * 180) / Math.PI) % 360) + 360) % 360)];
1390
+ }
1391
+ /**
1392
+ * A line's color and width when it sets neither: an arc's, or an edge's (the tool defaults).
1393
+ * @param directed - whether the line is an arc
1394
+ * @returns the color and width
1395
+ */
1396
+ function lineDefaults(directed) {
1397
+ return directed ? ARC_DEFAULTS : { color: pajekDefault("edge", "color"), width: pajekDefault("edge", "width") };
1398
+ }
1399
+ /**
1400
+ * A line's parameters from its values, leaving out the solid line Pajek draws by default (grey and 1 wide for an arc,
1401
+ * teal and 2 wide for an edge; `w` is half an edge's width). Arrows are Pajek's own: an arc has one at its target and
1402
+ * an edge none, so any other arrow is noted.
353
1403
  * @param get - the line's values
354
1404
  * @param directed - whether the line is an arc
355
1405
  * @param approximate - records approximations
@@ -358,18 +1408,24 @@ function vertexParams(get, approximate) {
358
1408
  function lineParams(get, directed, approximate) {
359
1409
  const out = new Map();
360
1410
  opaque(get, ["opacity"], approximate);
1411
+ const defaults = lineDefaults(directed);
361
1412
  const color = get("color");
362
- if (typeof color === "string" && color !== "#000000") {
1413
+ if (typeof color === "string" && color !== defaults.color) {
363
1414
  out.set("c", pajekColorText(color));
364
1415
  }
365
1416
  const width = get("width");
366
- if (typeof width === "number") {
367
- out.set("w", width);
1417
+ if (typeof width === "number" && width !== defaults.width) {
1418
+ out.set("w", directed ? width : Number((width / EDGE_WIDTH_PER_W).toPrecision(15)));
368
1419
  }
369
1420
  const lineStyle = get("lineStyle");
370
- if (typeof lineStyle === "string" && lineStyle !== "solid" && pajekDots(lineStyle, approximate)) {
1421
+ if (typeof lineStyle === "string" && lineStyle !== "solid" && pajekDots(lineStyle, out, directed, approximate)) {
371
1422
  out.set("p", "Dots");
372
1423
  }
1424
+ const position = get("arrowPosition");
1425
+ if (typeof position === "number" && position > 0) {
1426
+ out.set("ap", position);
1427
+ }
1428
+ lineLabelParams(get, out, approximate);
373
1429
  const target = get("targetArrow");
374
1430
  if (target !== null && target !== (directed ? "triangle" : "none")) {
375
1431
  approximate("targetArrow", target);
@@ -381,77 +1437,88 @@ function lineParams(get, directed, approximate) {
381
1437
  return out;
382
1438
  }
383
1439
  /**
384
- * Whether a line other than a solid one is written as Pajek's Dots: Pajek draws Solid and Dots only; a dashed kind is
1440
+ * A line's label parameters: its text `l` (a line break or a double quote written as Pajek can hold it, noted), its
1441
+ * color `lc`, size `fos` and font `font`.
1442
+ * @param get - the line's values
1443
+ * @param out - the parameters, changed in place
1444
+ * @param approximate - records approximations
1445
+ */
1446
+ function lineLabelParams(get, out, approximate) {
1447
+ const label = get("label");
1448
+ if (typeof label === "string" && label !== "") {
1449
+ const text = pajekLabelText(label);
1450
+ if (text !== label) {
1451
+ approximate("label", label);
1452
+ }
1453
+ out.set("l", text);
1454
+ }
1455
+ const labelColor = get("labelColor");
1456
+ if (typeof labelColor === "string") {
1457
+ out.set("lc", pajekColorText(labelColor));
1458
+ }
1459
+ const labelSize = get("labelSize");
1460
+ if (typeof labelSize === "number") {
1461
+ out.set("fos", labelSize);
1462
+ }
1463
+ fontParam(get, out);
1464
+ }
1465
+ /**
1466
+ * Whether a line other than a solid one is written as Pajek's Dots: Pajek draws Solid and Dots only, and its Dots
1467
+ * shows dots on a wide line and dashes on a thin one (`pajekDash`); the other of the two and any other dashed kind is
385
1468
  * nearest to Dots, any other line to Solid.
386
1469
  * @param lineStyle - the line style
1470
+ * @param params - the line's parameters written so far, its `w` among them
1471
+ * @param directed - whether the line is an arc
387
1472
  * @param approximate - records approximations
388
1473
  * @returns true for Dots
389
1474
  */
390
- function pajekDots(lineStyle, approximate) {
391
- if (lineStyle === "dotted") {
1475
+ function pajekDots(lineStyle, params, directed, approximate) {
1476
+ if (lineStyle === pajekDash((key) => params.get(key) ?? null, directed)) {
392
1477
  return true;
393
1478
  }
394
1479
  approximate("lineStyle", lineStyle);
395
- return lineStyle === "dashed" || lineStyle === "dash-dot" || lineStyle === "long-dash";
396
- }
397
- /**
398
- * Each element's values of the properties the writer writes, as a getter per element.
399
- * @param picture - each element's value of a property
400
- * @param target - nodes or edges
401
- * @returns the getter
402
- */
403
- function getter(picture, target) {
404
- const columns = new Map();
405
- for (const p of PAJEK_STYLE_CAPABILITIES[target]) {
406
- columns.set(p, picture(target, p));
407
- }
408
- return (i) => (property) => columns.get(property)?.[i] ?? null;
1480
+ return ["dashed", "dotted", "dash-dot", "long-dash"].includes(lineStyle);
409
1481
  }
410
1482
  /**
411
1483
  * For a file graphty wrote: where a value read from the parameters is what the writer writes for the block's own
412
- * value (a hexagon written as an ellipse, a dashed line as Dots), the block's exact value is the truth, so a re-import
1484
+ * value (a hexagon written as an ellipse, a dotted line as Dots), the block's exact value is the truth, so a re-import
413
1485
  * gives back the same rules; a value another program changed since stays the truth.
414
1486
  * @param snapshot - the graph
415
1487
  * @param text - the block's text
416
1488
  * @param read - the values read, changed in place
417
1489
  * @param read.node - the node values
418
1490
  * @param read.edge - the edge values
1491
+ * @param labels - whether the lines' labels are drawn
419
1492
  */
420
- function exactFromBlock(snapshot, text, read) {
421
- const parsed = parseStyleBlock(text, styleFingerprint(snapshot));
422
- const ex = parsed.ok ? blockStyles(parsed.block, snapshot, "pajek") : null;
423
- if (ex === null) {
424
- return;
425
- }
1493
+ function exactFromBlock(snapshot, text, read, labels) {
426
1494
  const notes = new StyleNotes();
427
1495
  const directed = directedEdges(snapshot);
428
- for (const target of ["node", "edge"]) {
429
- const n = target === "node" ? snapshot.nodeCount : snapshot.edgeCount;
430
- const get = getter((t, p) => resolveStyles(ex, t, p, snapshot), target);
431
- const values = read[target];
432
- for (let i = 0; i < n; i++) {
433
- const want = get(i);
434
- const back = writtenAndReadBack(target, want, directed[i], notes);
435
- for (const property of READ[target]) {
436
- const native = values[property]?.[i] ?? null;
437
- const w = want(property);
438
- if (w !== null && native !== w && native === (back.get(property) ?? null)) {
439
- values[property] ?? (values[property] = new Array(n).fill(null));
440
- values[property][i] = w;
441
- }
442
- }
443
- }
444
- }
1496
+ takeFromBlock(snapshot, text, "pajek", (target) => ({
1497
+ values: read[target],
1498
+ properties: READ[target],
1499
+ writes: PAJEK_STYLE_CAPABILITIES[target],
1500
+ readBack: (i, want) => {
1501
+ const back = writtenAndReadBack(target, want, directed[i], notes, labels);
1502
+ return (property) => back.get(property) ?? null;
1503
+ },
1504
+ // a label the block places by a side clears the offsets its `lphi` reads back as
1505
+ take: (property, wanted) => wanted !== null || LABEL_PLACE.has(property) || OUTLINE.has(property),
1506
+ }));
445
1507
  }
1508
+ /** The outline a shape written as `diamond` reads back as, which the block's own shape clears. */
1509
+ const OUTLINE = new Set(["shapePoints", "shapePointsStretch"]);
1510
+ /** The label place properties a side written as `lphi` reads back as. */
1511
+ const LABEL_PLACE = new Set(["labelOffsetX", "labelOffsetY", "labelShiftX"]);
446
1512
  /**
447
1513
  * An element's values written as the writer writes them and read back as the reader reads them.
448
1514
  * @param target - nodes or edges
449
1515
  * @param want - its values
450
1516
  * @param directed - for a line, whether it is an arc
451
1517
  * @param notes - a scratch for the notes the round trip makes
1518
+ * @param labels - whether the lines' labels are drawn
452
1519
  * @returns the values read back, by property
453
1520
  */
454
- function writtenAndReadBack(target, want, directed, notes) {
1521
+ function writtenAndReadBack(target, want, directed, notes, labels) {
455
1522
  const ignore = () => undefined;
456
1523
  const params = target === "node" ? vertexParams(want, ignore) : lineParams(want, directed, ignore);
457
1524
  const back = new Map();
@@ -459,11 +1526,28 @@ function writtenAndReadBack(target, want, directed, notes) {
459
1526
  if (typeof label === "string") {
460
1527
  params.set(LABEL_COLUMN, pajekLabelText(label));
461
1528
  }
462
- (target === "node" ? readVertex : readLine)((key) => params.get(key) ?? null, (property, value) => {
1529
+ // what the writer restates so that nothing is carried to this element (`restateCarried`)
1530
+ if (target === "node" && [...params.keys()].every((key) => key === LABEL_COLUMN)) {
1531
+ params.set(SHAPE_COLUMN, "ellipse");
1532
+ }
1533
+ for (const key of target === "edge" ? CARRIED.edge : []) {
1534
+ if (!params.has(key)) {
1535
+ params.set(key, lineRestated(key, directed));
1536
+ }
1537
+ }
1538
+ const get = (key) => params.get(key) ?? null;
1539
+ const put = (property, value) => {
463
1540
  if (value !== null) {
464
1541
  back.set(property, value);
465
1542
  }
466
- }, (property) => ({ notes, target, property }));
1543
+ };
1544
+ const at = (property) => ({ notes, target, property });
1545
+ if (target === "node") {
1546
+ readVertex(get, put, at);
1547
+ }
1548
+ else {
1549
+ readLine(get, put, at, directed, labels);
1550
+ }
467
1551
  return back;
468
1552
  }
469
1553
  /**
@@ -486,10 +1570,15 @@ export function pajekStyledExport(snapshot, input) {
486
1570
  const approximate = (property, value) => {
487
1571
  approximated.add(target, property, value);
488
1572
  };
489
- const get = getter((t, p) => input.picture(t, p), target);
1573
+ const get = elementValues((t, p) => input.picture(t, p), target, PAJEK_STYLE_CAPABILITIES[target]);
490
1574
  const n = target === "node" ? snapshot.nodeCount : snapshot.edgeCount;
491
1575
  const params = (i) => target === "node" ? vertexParams(get(i), approximate) : lineParams(get(i), directed[i], approximate);
492
- replaceParamColumns(table, target === "node" ? [SHAPE_COLUMN, ...NODE_KEYS] : EDGE_KEYS, paramColumns(n, params));
1576
+ const columns = paramColumns(n, params);
1577
+ if (target === "edge") {
1578
+ keepLineLabels(snapshot, columns);
1579
+ }
1580
+ restateCarried(target, columns, directed);
1581
+ replaceParamColumns(table, target === "node" ? [SHAPE_COLUMN, ...NODE_KEYS] : EDGE_KEYS, columns);
493
1582
  }
494
1583
  out.nodes.set(LABEL_COLUMN, drawnLabels(input, snapshot.nodeCount, approximated), { dtype: "string", role: "label" }, {
495
1584
  replaceRole: true,
@@ -499,6 +1588,29 @@ export function pajekStyledExport(snapshot, input) {
499
1588
  notes.push(...styleBlockLosses(block, input.rules.styles.rules.length, "size"));
500
1589
  return { snapshot: out, comment: PAJEK_STYLE_COMMENT + block, notes };
501
1590
  }
1591
+ /**
1592
+ * Keeps each line's own label `l` where graphty draws none: Pajek draws no line label by default (`drawsLineLabels`),
1593
+ * so a label the file holds is not drawn, and writing it back keeps it for a Draw window that marks lines with labels.
1594
+ * @param snapshot - the graph handed to the exporter
1595
+ * @param columns - the written edge columns, by key, changed in place
1596
+ */
1597
+ function keepLineLabels(snapshot, columns) {
1598
+ if (!snapshot.edges.has("l")) {
1599
+ return;
1600
+ }
1601
+ const own = (e) => plainCell(snapshot.edges.value("l", e));
1602
+ let col = columns.get("l");
1603
+ for (let e = 0; e < snapshot.edgeCount; e++) {
1604
+ const v = own(e);
1605
+ if (typeof v === "string" && v !== "" && (col?.[e] ?? null) === null) {
1606
+ col ?? (col = new Array(snapshot.edgeCount).fill(null));
1607
+ col[e] = pajekLabelText(v);
1608
+ }
1609
+ }
1610
+ if (col !== undefined) {
1611
+ columns.set("l", col);
1612
+ }
1613
+ }
502
1614
  /**
503
1615
  * Each vertex's label as graphty draws it; a vertex graphty draws without one gets an empty label, which Pajek draws
504
1616
  * as nothing (with no label, Pajek writes and draws the vertex's id).
@@ -547,6 +1659,59 @@ function replaceParamColumns(table, keys, columns) {
547
1659
  table.set(key, col, { dtype: numeric ? "f64" : "string" });
548
1660
  }
549
1661
  }
1662
+ /**
1663
+ * Keeps Pajek from drawing an element with the parameters of the one before it (`CARRIED`): a line writes Pajek's own
1664
+ * default for each parameter another line writes and it leaves out, and a vertex that writes no parameter while
1665
+ * another does writes its shape, `ellipse`, which starts it again from Pajek's defaults.
1666
+ * @param target - nodes or edges
1667
+ * @param columns - the written columns, by key, changed in place
1668
+ * @param directed - for each line, whether it is an arc
1669
+ */
1670
+ function restateCarried(target, columns, directed) {
1671
+ if (target === "node") {
1672
+ const all = [...columns.values()];
1673
+ if (all.length === 0) {
1674
+ return;
1675
+ }
1676
+ const n = all[0].length;
1677
+ const shape = columns.get(SHAPE_COLUMN) ?? new Array(n).fill(null);
1678
+ for (let i = 0; i < n; i++) {
1679
+ if (all.every((col) => col[i] === null)) {
1680
+ shape[i] = "ellipse";
1681
+ }
1682
+ }
1683
+ columns.set(SHAPE_COLUMN, shape);
1684
+ return;
1685
+ }
1686
+ for (const key of CARRIED.edge) {
1687
+ const col = columns.get(key);
1688
+ if (col === undefined) {
1689
+ continue;
1690
+ }
1691
+ for (let i = 0; i < col.length; i++) {
1692
+ col[i] ?? (col[i] = lineRestated(key, directed[i]));
1693
+ }
1694
+ }
1695
+ }
1696
+ /**
1697
+ * What a line writes for a carried parameter it leaves at Pajek's default.
1698
+ * @param key - the parameter
1699
+ * @param directed - whether the line is an arc
1700
+ * @returns the value written
1701
+ */
1702
+ function lineRestated(key, directed) {
1703
+ const defaults = lineDefaults(directed);
1704
+ switch (key) {
1705
+ case "c":
1706
+ return pajekColorText(String(defaults.color));
1707
+ case "w":
1708
+ return directed ? Number(defaults.width) : Number(defaults.width) / EDGE_WIDTH_PER_W;
1709
+ case "p":
1710
+ return "Solid";
1711
+ default:
1712
+ return 0;
1713
+ }
1714
+ }
550
1715
  /**
551
1716
  * Every element's parameters, as columns.
552
1717
  * @param n - the element count