@graphty/graph-io 0.3.48 → 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 (570) hide show
  1. package/dist/chunks/{approximations-C2riR4NT.js → approximations-Bzn3L-je.js} +2 -2
  2. package/dist/chunks/{approximations-C2riR4NT.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-Cu22ewuS.js → block-iptrlMBb.js} +906 -164
  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-CV_Bhcyi.js → codes-BE2xir2k.js} +6 -2
  10. package/dist/chunks/codes-BE2xir2k.js.map +1 -0
  11. package/dist/chunks/{constants-D0LqcsLJ.js → constants-CKkYLPtt.js} +2 -2
  12. package/dist/chunks/{constants-D0LqcsLJ.js.map → constants-CKkYLPtt.js.map} +1 -1
  13. package/dist/chunks/{context-cgmmOxZ2.js → context-C3p0RQxR.js} +5 -4
  14. package/dist/chunks/{context-cgmmOxZ2.js.map → context-C3p0RQxR.js.map} +1 -1
  15. package/dist/chunks/{convert-BcQ8_jMo.js → convert-Ct2zelbQ.js} +7 -2
  16. package/dist/chunks/convert-Ct2zelbQ.js.map +1 -0
  17. package/dist/chunks/{credentials-BiQsnMTb.js → credentials-DXHx7nwR.js} +16 -14
  18. package/dist/chunks/credentials-DXHx7nwR.js.map +1 -0
  19. package/dist/chunks/{cx-export-BEeF6ymo.js → cx-export-Bt6NoqTQ.js} +3 -3
  20. package/dist/chunks/{cx-export-BEeF6ymo.js.map → cx-export-Bt6NoqTQ.js.map} +1 -1
  21. package/dist/chunks/descriptor-B28U25x4.js +60 -0
  22. package/dist/chunks/descriptor-B28U25x4.js.map +1 -0
  23. package/dist/chunks/{descriptor-BJ-W0Jd-.js → descriptor-DLA5kINx.js} +7 -2
  24. package/dist/chunks/descriptor-DLA5kINx.js.map +1 -0
  25. package/dist/chunks/{emit-CD8xnY8s.js → emit-BwHQkZle.js} +1660 -133
  26. package/dist/chunks/emit-BwHQkZle.js.map +1 -0
  27. package/dist/chunks/{escape-DH2Egt-l.js → escape-CuCIzNMB.js} +8 -8
  28. package/dist/chunks/{escape-DH2Egt-l.js.map → escape-CuCIzNMB.js.map} +1 -1
  29. package/dist/chunks/{export-CZ7VRm4I.js → export-Cha4dRFz.js} +45 -387
  30. package/dist/chunks/export-Cha4dRFz.js.map +1 -0
  31. package/dist/chunks/{exporter-Dcw7Ldtq.js → exporter-BP6otMO6.js} +6 -6
  32. package/dist/chunks/{exporter-Dcw7Ldtq.js.map → exporter-BP6otMO6.js.map} +1 -1
  33. package/dist/chunks/{exporter-bxxjOrDZ.js → exporter-D2CETOMK.js} +1222 -156
  34. package/dist/chunks/exporter-D2CETOMK.js.map +1 -0
  35. package/dist/chunks/{exporter-BIdaoIgh.js → exporter-D9yMtocA.js} +7 -7
  36. package/dist/chunks/{exporter-BIdaoIgh.js.map → exporter-D9yMtocA.js.map} +1 -1
  37. package/dist/chunks/{exporter-DtVU80Fa.js → exporter-_jrBTnos.js} +9 -8
  38. package/dist/chunks/{exporter-DtVU80Fa.js.map → exporter-_jrBTnos.js.map} +1 -1
  39. package/dist/chunks/{exporter-ChjL5fmP.js → exporter-nDfxIK5D.js} +9 -8
  40. package/dist/chunks/{exporter-ChjL5fmP.js.map → exporter-nDfxIK5D.js.map} +1 -1
  41. package/dist/chunks/format-BXiAb-1h.js +408 -0
  42. package/dist/chunks/format-BXiAb-1h.js.map +1 -0
  43. package/dist/chunks/{generic-CP6YD34u.js → generic-ymWCETAJ.js} +387 -31
  44. package/dist/chunks/generic-ymWCETAJ.js.map +1 -0
  45. package/dist/chunks/{importer-e3huMZbm.js → importer-B92x1xY5.js} +14 -10
  46. package/dist/chunks/importer-B92x1xY5.js.map +1 -0
  47. package/dist/chunks/{importer-B87_fmVx.js → importer-CT9mJ1nn.js} +326 -84
  48. package/dist/chunks/importer-CT9mJ1nn.js.map +1 -0
  49. package/dist/chunks/{importer-CB_zV5_L.js → importer-DaLTjbds.js} +116 -1102
  50. package/dist/chunks/importer-DaLTjbds.js.map +1 -0
  51. package/dist/chunks/{importer-DPZDN40-.js → importer-GREKMdIf.js} +25 -17
  52. package/dist/chunks/importer-GREKMdIf.js.map +1 -0
  53. package/dist/chunks/{importer-Bji2MeWr.js → importer-PqaaKKnY.js} +13 -10
  54. package/dist/chunks/{importer-Bji2MeWr.js.map → importer-PqaaKKnY.js.map} +1 -1
  55. package/dist/chunks/{importer-Cyy6UseH.js → importer-Vn5QvmmJ.js} +66 -13
  56. package/dist/chunks/importer-Vn5QvmmJ.js.map +1 -0
  57. package/dist/chunks/{importer-CVT-JyDE.js → importer-vRq4h3j5.js} +1469 -356
  58. package/dist/chunks/importer-vRq4h3j5.js.map +1 -0
  59. package/dist/chunks/{input-Ccg9I22A.js → input-CAxt_aV-.js} +4 -4
  60. package/dist/chunks/{input-Ccg9I22A.js.map → input-CAxt_aV-.js.map} +1 -1
  61. package/dist/chunks/{json-elements-By172SVq.js → json-elements-Cq76WjnZ.js} +4 -4
  62. package/dist/chunks/{json-elements-By172SVq.js.map → json-elements-Cq76WjnZ.js.map} +1 -1
  63. package/dist/chunks/{lexicon-u2SI5xcx.js → lexicon-Clf4QIyl.js} +282 -74
  64. package/dist/chunks/lexicon-Clf4QIyl.js.map +1 -0
  65. package/dist/chunks/{ontology-export-BwgMyuF0.js → ontology-export-OMo91mb0.js} +4 -4
  66. package/dist/chunks/{ontology-export-BwgMyuF0.js.map → ontology-export-OMo91mb0.js.map} +1 -1
  67. package/dist/chunks/{records-Cgvxz-Vx.js → records-NJiYvekn.js} +2 -2
  68. package/dist/chunks/{records-Cgvxz-Vx.js.map → records-NJiYvekn.js.map} +1 -1
  69. package/dist/chunks/{report-CgdsL9Hb.js → report-CwMfYa9J.js} +23 -23
  70. package/dist/chunks/{report-CgdsL9Hb.js.map → report-CwMfYa9J.js.map} +1 -1
  71. package/dist/chunks/round-trip-Zm3_ivgq.js +79 -0
  72. package/dist/chunks/round-trip-Zm3_ivgq.js.map +1 -0
  73. package/dist/chunks/{sigv4-LkAzsLAu.js → sigv4-EokFic1V.js} +5 -5
  74. package/dist/chunks/sigv4-EokFic1V.js.map +1 -0
  75. package/dist/chunks/{styles-CaABMoO1.js → styles-CCs214_3.js} +1237 -138
  76. package/dist/chunks/styles-CCs214_3.js.map +1 -0
  77. package/dist/chunks/styles-Cm62yyQX.js +2812 -0
  78. package/dist/chunks/styles-Cm62yyQX.js.map +1 -0
  79. package/dist/chunks/styles-DPQQIig4.js +1928 -0
  80. package/dist/chunks/styles-DPQQIig4.js.map +1 -0
  81. package/dist/chunks/{styles-yed-Cs1nmrjn.js → styles-yed-UMFdNqze.js} +503 -172
  82. package/dist/chunks/styles-yed-UMFdNqze.js.map +1 -0
  83. package/dist/chunks/{text-BuKQVMz2.js → text-ystE2bYi.js} +2 -2
  84. package/dist/chunks/{text-BuKQVMz2.js.map → text-ystE2bYi.js.map} +1 -1
  85. package/dist/csv.js +7 -7
  86. package/dist/cx.js +2 -2
  87. package/dist/cx2.js +2 -2
  88. package/dist/cys.js +1 -1
  89. package/dist/dot.js +5 -4
  90. package/dist/dot.js.map +1 -1
  91. package/dist/gexf.js +42 -12
  92. package/dist/gexf.js.map +1 -1
  93. package/dist/gml.js +847 -193
  94. package/dist/gml.js.map +1 -1
  95. package/dist/graph-io.js +232 -220
  96. package/dist/graph-io.js.map +1 -1
  97. package/dist/graphml.js +3 -3
  98. package/dist/json.js +3 -2
  99. package/dist/neo4j.js +6 -6
  100. package/dist/obo.js +1 -1
  101. package/dist/pajek.js +1 -1
  102. package/dist/positions.js +45 -3
  103. package/dist/positions.js.map +1 -1
  104. package/dist/sources-cypher.js +138 -23
  105. package/dist/sources-cypher.js.map +1 -1
  106. package/dist/sources-ndex.js +2 -2
  107. package/dist/sources-rest.js +16 -6
  108. package/dist/sources-rest.js.map +1 -1
  109. package/dist/sources-sparql.d.ts +1 -0
  110. package/dist/sources-sparql.js +405 -0
  111. package/dist/sources-sparql.js.map +1 -0
  112. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  113. package/dist/src/formats/cx/importer.js +5 -1
  114. package/dist/src/formats/cx/importer.js.map +1 -1
  115. package/dist/src/formats/cx/styles.d.ts +24 -1
  116. package/dist/src/formats/cx/styles.d.ts.map +1 -1
  117. package/dist/src/formats/cx/styles.js +117 -11
  118. package/dist/src/formats/cx/styles.js.map +1 -1
  119. package/dist/src/formats/cx2/importer.d.ts.map +1 -1
  120. package/dist/src/formats/cx2/importer.js +1 -0
  121. package/dist/src/formats/cx2/importer.js.map +1 -1
  122. package/dist/src/formats/cx2/styles.d.ts.map +1 -1
  123. package/dist/src/formats/cx2/styles.js +3 -1
  124. package/dist/src/formats/cx2/styles.js.map +1 -1
  125. package/dist/src/formats/cys/importer.d.ts.map +1 -1
  126. package/dist/src/formats/cys/importer.js +1 -0
  127. package/dist/src/formats/cys/importer.js.map +1 -1
  128. package/dist/src/formats/cys/styles.d.ts +2 -0
  129. package/dist/src/formats/cys/styles.d.ts.map +1 -1
  130. package/dist/src/formats/cys/styles.js +15 -7
  131. package/dist/src/formats/cys/styles.js.map +1 -1
  132. package/dist/src/formats/dot/drawing.d.ts +98 -0
  133. package/dist/src/formats/dot/drawing.d.ts.map +1 -0
  134. package/dist/src/formats/dot/drawing.js +734 -0
  135. package/dist/src/formats/dot/drawing.js.map +1 -0
  136. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  137. package/dist/src/formats/dot/importer.js +108 -31
  138. package/dist/src/formats/dot/importer.js.map +1 -1
  139. package/dist/src/formats/dot/label-places.d.ts +34 -0
  140. package/dist/src/formats/dot/label-places.d.ts.map +1 -0
  141. package/dist/src/formats/dot/label-places.js +179 -0
  142. package/dist/src/formats/dot/label-places.js.map +1 -0
  143. package/dist/src/formats/dot/record.d.ts +50 -0
  144. package/dist/src/formats/dot/record.d.ts.map +1 -0
  145. package/dist/src/formats/dot/record.js +275 -0
  146. package/dist/src/formats/dot/record.js.map +1 -0
  147. package/dist/src/formats/dot/styles.d.ts +62 -2
  148. package/dist/src/formats/dot/styles.d.ts.map +1 -1
  149. package/dist/src/formats/dot/styles.js +1454 -119
  150. package/dist/src/formats/dot/styles.js.map +1 -1
  151. package/dist/src/formats/gexf/dialog-metrics.d.ts +15 -0
  152. package/dist/src/formats/gexf/dialog-metrics.d.ts.map +1 -0
  153. package/dist/src/formats/gexf/dialog-metrics.js +59 -0
  154. package/dist/src/formats/gexf/dialog-metrics.js.map +1 -0
  155. package/dist/src/formats/gexf/importer.d.ts +7 -0
  156. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  157. package/dist/src/formats/gexf/importer.js +41 -5
  158. package/dist/src/formats/gexf/importer.js.map +1 -1
  159. package/dist/src/formats/gexf/preview.d.ts +77 -0
  160. package/dist/src/formats/gexf/preview.d.ts.map +1 -0
  161. package/dist/src/formats/gexf/preview.js +191 -0
  162. package/dist/src/formats/gexf/preview.js.map +1 -0
  163. package/dist/src/formats/gexf/schema.d.ts.map +1 -1
  164. package/dist/src/formats/gexf/schema.js +2 -1
  165. package/dist/src/formats/gexf/schema.js.map +1 -1
  166. package/dist/src/formats/gexf/styles.d.ts +58 -31
  167. package/dist/src/formats/gexf/styles.d.ts.map +1 -1
  168. package/dist/src/formats/gexf/styles.js +848 -225
  169. package/dist/src/formats/gexf/styles.js.map +1 -1
  170. package/dist/src/formats/gml/importer.d.ts +5 -2
  171. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  172. package/dist/src/formats/gml/importer.js +258 -71
  173. package/dist/src/formats/gml/importer.js.map +1 -1
  174. package/dist/src/formats/gml/index.d.ts +1 -1
  175. package/dist/src/formats/gml/index.d.ts.map +1 -1
  176. package/dist/src/formats/gml/index.js +1 -1
  177. package/dist/src/formats/gml/index.js.map +1 -1
  178. package/dist/src/formats/gml/positions.d.ts +7 -0
  179. package/dist/src/formats/gml/positions.d.ts.map +1 -1
  180. package/dist/src/formats/gml/positions.js +29 -7
  181. package/dist/src/formats/gml/positions.js.map +1 -1
  182. package/dist/src/formats/gml/styles.d.ts.map +1 -1
  183. package/dist/src/formats/gml/styles.js +753 -101
  184. package/dist/src/formats/gml/styles.js.map +1 -1
  185. package/dist/src/formats/graphml/styles-plain.d.ts.map +1 -1
  186. package/dist/src/formats/graphml/styles-plain.js +6 -10
  187. package/dist/src/formats/graphml/styles-plain.js.map +1 -1
  188. package/dist/src/formats/graphml/styles-yed.d.ts +21 -15
  189. package/dist/src/formats/graphml/styles-yed.d.ts.map +1 -1
  190. package/dist/src/formats/graphml/styles-yed.js +692 -161
  191. package/dist/src/formats/graphml/styles-yed.js.map +1 -1
  192. package/dist/src/formats/graphml/styles-yfiles3.d.ts +1 -1
  193. package/dist/src/formats/graphml/styles-yfiles3.d.ts.map +1 -1
  194. package/dist/src/formats/graphml/styles-yfiles3.js +429 -64
  195. package/dist/src/formats/graphml/styles-yfiles3.js.map +1 -1
  196. package/dist/src/formats/graphml/yfiles.d.ts +3 -3
  197. package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
  198. package/dist/src/formats/graphml/yfiles.js +16 -6
  199. package/dist/src/formats/graphml/yfiles.js.map +1 -1
  200. package/dist/src/formats/json/dialect.d.ts +3 -2
  201. package/dist/src/formats/json/dialect.d.ts.map +1 -1
  202. package/dist/src/formats/json/dialect.js +39 -5
  203. package/dist/src/formats/json/dialect.js.map +1 -1
  204. package/dist/src/formats/json/importer.d.ts +13 -2
  205. package/dist/src/formats/json/importer.d.ts.map +1 -1
  206. package/dist/src/formats/json/importer.js +42 -6
  207. package/dist/src/formats/json/importer.js.map +1 -1
  208. package/dist/src/formats/json/index.d.ts +1 -1
  209. package/dist/src/formats/json/index.d.ts.map +1 -1
  210. package/dist/src/formats/json/index.js +1 -1
  211. package/dist/src/formats/json/index.js.map +1 -1
  212. package/dist/src/formats/json/positions.d.ts +5 -2
  213. package/dist/src/formats/json/positions.d.ts.map +1 -1
  214. package/dist/src/formats/json/positions.js +20 -4
  215. package/dist/src/formats/json/positions.js.map +1 -1
  216. package/dist/src/formats/json/styles.d.ts +12 -1
  217. package/dist/src/formats/json/styles.d.ts.map +1 -1
  218. package/dist/src/formats/json/styles.js +1755 -136
  219. package/dist/src/formats/json/styles.js.map +1 -1
  220. package/dist/src/formats/pajek/draw.d.ts +96 -0
  221. package/dist/src/formats/pajek/draw.d.ts.map +1 -0
  222. package/dist/src/formats/pajek/draw.js +372 -0
  223. package/dist/src/formats/pajek/draw.js.map +1 -0
  224. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  225. package/dist/src/formats/pajek/exporter.js +70 -51
  226. package/dist/src/formats/pajek/exporter.js.map +1 -1
  227. package/dist/src/formats/pajek/importer.d.ts +9 -0
  228. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  229. package/dist/src/formats/pajek/importer.js +233 -102
  230. package/dist/src/formats/pajek/importer.js.map +1 -1
  231. package/dist/src/formats/pajek/index.d.ts +1 -0
  232. package/dist/src/formats/pajek/index.d.ts.map +1 -1
  233. package/dist/src/formats/pajek/index.js.map +1 -1
  234. package/dist/src/formats/pajek/styles.d.ts +15 -7
  235. package/dist/src/formats/pajek/styles.d.ts.map +1 -1
  236. package/dist/src/formats/pajek/styles.js +1278 -114
  237. package/dist/src/formats/pajek/styles.js.map +1 -1
  238. package/dist/src/formats/pajek/syntax.d.ts +10 -1
  239. package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
  240. package/dist/src/formats/pajek/syntax.js +26 -2
  241. package/dist/src/formats/pajek/syntax.js.map +1 -1
  242. package/dist/src/formats/xgmml/emit.d.ts +1 -0
  243. package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
  244. package/dist/src/formats/xgmml/emit.js +65 -5
  245. package/dist/src/formats/xgmml/emit.js.map +1 -1
  246. package/dist/src/formats/xgmml/styles.d.ts +23 -3
  247. package/dist/src/formats/xgmml/styles.d.ts.map +1 -1
  248. package/dist/src/formats/xgmml/styles.js +277 -60
  249. package/dist/src/formats/xgmml/styles.js.map +1 -1
  250. package/dist/src/index.d.ts +4 -3
  251. package/dist/src/index.d.ts.map +1 -1
  252. package/dist/src/index.js +4 -3
  253. package/dist/src/index.js.map +1 -1
  254. package/dist/src/positions/convert.d.ts.map +1 -1
  255. package/dist/src/positions/convert.js +11 -1
  256. package/dist/src/positions/convert.js.map +1 -1
  257. package/dist/src/positions/extract.d.ts.map +1 -1
  258. package/dist/src/positions/extract.js +53 -1
  259. package/dist/src/positions/extract.js.map +1 -1
  260. package/dist/src/positions/index.d.ts +1 -1
  261. package/dist/src/positions/index.d.ts.map +1 -1
  262. package/dist/src/positions/types.d.ts +59 -0
  263. package/dist/src/positions/types.d.ts.map +1 -1
  264. package/dist/src/sources/builtins.d.ts +1 -1
  265. package/dist/src/sources/builtins.d.ts.map +1 -1
  266. package/dist/src/sources/builtins.js +8 -2
  267. package/dist/src/sources/builtins.js.map +1 -1
  268. package/dist/src/sources/context.d.ts.map +1 -1
  269. package/dist/src/sources/context.js +1 -0
  270. package/dist/src/sources/context.js.map +1 -1
  271. package/dist/src/sources/cypher/descriptor.d.ts.map +1 -1
  272. package/dist/src/sources/cypher/descriptor.js +5 -0
  273. package/dist/src/sources/cypher/descriptor.js.map +1 -1
  274. package/dist/src/sources/cypher/index.d.ts.map +1 -1
  275. package/dist/src/sources/cypher/index.js +124 -18
  276. package/dist/src/sources/cypher/index.js.map +1 -1
  277. package/dist/src/sources/cypher/params.d.ts +1 -1
  278. package/dist/src/sources/cypher/params.d.ts.map +1 -1
  279. package/dist/src/sources/cypher/query-builder.d.ts +17 -0
  280. package/dist/src/sources/cypher/query-builder.d.ts.map +1 -1
  281. package/dist/src/sources/cypher/query-builder.js +31 -0
  282. package/dist/src/sources/cypher/query-builder.js.map +1 -1
  283. package/dist/src/sources/ids.d.ts +5 -0
  284. package/dist/src/sources/ids.d.ts.map +1 -1
  285. package/dist/src/sources/ids.js +5 -0
  286. package/dist/src/sources/ids.js.map +1 -1
  287. package/dist/src/sources/params.d.ts +3 -0
  288. package/dist/src/sources/params.d.ts.map +1 -1
  289. package/dist/src/sources/rest/descriptor.d.ts.map +1 -1
  290. package/dist/src/sources/rest/descriptor.js +5 -0
  291. package/dist/src/sources/rest/descriptor.js.map +1 -1
  292. package/dist/src/sources/rest/source.d.ts.map +1 -1
  293. package/dist/src/sources/rest/source.js +15 -0
  294. package/dist/src/sources/rest/source.js.map +1 -1
  295. package/dist/src/sources/sigv4.d.ts +5 -3
  296. package/dist/src/sources/sigv4.d.ts.map +1 -1
  297. package/dist/src/sources/sigv4.js +6 -4
  298. package/dist/src/sources/sigv4.js.map +1 -1
  299. package/dist/src/sources/sparql/descriptor.d.ts +10 -0
  300. package/dist/src/sources/sparql/descriptor.d.ts.map +1 -0
  301. package/dist/src/sources/sparql/descriptor.js +64 -0
  302. package/dist/src/sources/sparql/descriptor.js.map +1 -0
  303. package/dist/src/sources/sparql/index.d.ts +28 -0
  304. package/dist/src/sources/sparql/index.d.ts.map +1 -0
  305. package/dist/src/sources/sparql/index.js +314 -0
  306. package/dist/src/sources/sparql/index.js.map +1 -0
  307. package/dist/src/sources/sparql/ntriples.d.ts +69 -0
  308. package/dist/src/sources/sparql/ntriples.d.ts.map +1 -0
  309. package/dist/src/sources/sparql/ntriples.js +180 -0
  310. package/dist/src/sources/sparql/ntriples.js.map +1 -0
  311. package/dist/src/sources/sparql/params.d.ts +27 -0
  312. package/dist/src/sources/sparql/params.d.ts.map +1 -0
  313. package/dist/src/sources/sparql/params.js +5 -0
  314. package/dist/src/sources/sparql/params.js.map +1 -0
  315. package/dist/src/sources/sparql/query.d.ts +72 -0
  316. package/dist/src/sources/sparql/query.d.ts.map +1 -0
  317. package/dist/src/sources/sparql/query.js +113 -0
  318. package/dist/src/sources/sparql/query.js.map +1 -0
  319. package/dist/src/sources/types.d.ts +31 -0
  320. package/dist/src/sources/types.d.ts.map +1 -1
  321. package/dist/src/styles/annotations.d.ts +61 -5
  322. package/dist/src/styles/annotations.d.ts.map +1 -1
  323. package/dist/src/styles/annotations.js +130 -22
  324. package/dist/src/styles/annotations.js.map +1 -1
  325. package/dist/src/styles/canon/bends.d.ts +46 -0
  326. package/dist/src/styles/canon/bends.d.ts.map +1 -1
  327. package/dist/src/styles/canon/bends.js +123 -0
  328. package/dist/src/styles/canon/bends.js.map +1 -1
  329. package/dist/src/styles/canon/color-tables.d.ts +6 -1
  330. package/dist/src/styles/canon/color-tables.d.ts.map +1 -1
  331. package/dist/src/styles/canon/color-tables.js +10 -4
  332. package/dist/src/styles/canon/color-tables.js.map +1 -1
  333. package/dist/src/styles/canon/color.d.ts +3 -1
  334. package/dist/src/styles/canon/color.d.ts.map +1 -1
  335. package/dist/src/styles/canon/color.js +103 -3
  336. package/dist/src/styles/canon/color.js.map +1 -1
  337. package/dist/src/styles/canon/enums.d.ts +2 -2
  338. package/dist/src/styles/canon/enums.d.ts.map +1 -1
  339. package/dist/src/styles/canon/enums.js +81 -7
  340. package/dist/src/styles/canon/enums.js.map +1 -1
  341. package/dist/src/styles/canon/graphviz.d.ts +12 -3
  342. package/dist/src/styles/canon/graphviz.d.ts.map +1 -1
  343. package/dist/src/styles/canon/graphviz.js +57 -9
  344. package/dist/src/styles/canon/graphviz.js.map +1 -1
  345. package/dist/src/styles/canon/number.d.ts +8 -0
  346. package/dist/src/styles/canon/number.d.ts.map +1 -1
  347. package/dist/src/styles/canon/number.js +18 -0
  348. package/dist/src/styles/canon/number.js.map +1 -1
  349. package/dist/src/styles/canon/text.d.ts +29 -2
  350. package/dist/src/styles/canon/text.d.ts.map +1 -1
  351. package/dist/src/styles/canon/text.js +156 -16
  352. package/dist/src/styles/canon/text.js.map +1 -1
  353. package/dist/src/styles/codes.d.ts +2 -0
  354. package/dist/src/styles/codes.d.ts.map +1 -1
  355. package/dist/src/styles/codes.js +2 -0
  356. package/dist/src/styles/codes.js.map +1 -1
  357. package/dist/src/styles/cyjs/cascade.d.ts.map +1 -1
  358. package/dist/src/styles/cyjs/cascade.js +1015 -79
  359. package/dist/src/styles/cyjs/cascade.js.map +1 -1
  360. package/dist/src/styles/cyjs/defaults-table.d.ts.map +1 -1
  361. package/dist/src/styles/cyjs/defaults-table.js +3 -0
  362. package/dist/src/styles/cyjs/defaults-table.js.map +1 -1
  363. package/dist/src/styles/cyjs/emit.d.ts.map +1 -1
  364. package/dist/src/styles/cyjs/emit.js +202 -9
  365. package/dist/src/styles/cyjs/emit.js.map +1 -1
  366. package/dist/src/styles/cyjs/face.d.ts +20 -0
  367. package/dist/src/styles/cyjs/face.d.ts.map +1 -0
  368. package/dist/src/styles/cyjs/face.js +332 -0
  369. package/dist/src/styles/cyjs/face.js.map +1 -0
  370. package/dist/src/styles/cyjs/mappers.d.ts +44 -1
  371. package/dist/src/styles/cyjs/mappers.d.ts.map +1 -1
  372. package/dist/src/styles/cyjs/mappers.js +461 -26
  373. package/dist/src/styles/cyjs/mappers.js.map +1 -1
  374. package/dist/src/styles/cyjs/routes.d.ts +53 -0
  375. package/dist/src/styles/cyjs/routes.d.ts.map +1 -0
  376. package/dist/src/styles/cyjs/routes.js +360 -0
  377. package/dist/src/styles/cyjs/routes.js.map +1 -0
  378. package/dist/src/styles/cytoscape/charts.d.ts +23 -0
  379. package/dist/src/styles/cytoscape/charts.d.ts.map +1 -0
  380. package/dist/src/styles/cytoscape/charts.js +560 -0
  381. package/dist/src/styles/cytoscape/charts.js.map +1 -0
  382. package/dist/src/styles/cytoscape/emit.d.ts.map +1 -1
  383. package/dist/src/styles/cytoscape/emit.js +156 -48
  384. package/dist/src/styles/cytoscape/emit.js.map +1 -1
  385. package/dist/src/styles/cytoscape/lexicon.d.ts +91 -3
  386. package/dist/src/styles/cytoscape/lexicon.d.ts.map +1 -1
  387. package/dist/src/styles/cytoscape/lexicon.js +387 -77
  388. package/dist/src/styles/cytoscape/lexicon.js.map +1 -1
  389. package/dist/src/styles/cytoscape/mappings.d.ts +30 -0
  390. package/dist/src/styles/cytoscape/mappings.d.ts.map +1 -1
  391. package/dist/src/styles/cytoscape/mappings.js +92 -0
  392. package/dist/src/styles/cytoscape/mappings.js.map +1 -1
  393. package/dist/src/styles/cytoscape/resolve.d.ts +42 -2
  394. package/dist/src/styles/cytoscape/resolve.d.ts.map +1 -1
  395. package/dist/src/styles/cytoscape/resolve.js +623 -17
  396. package/dist/src/styles/cytoscape/resolve.js.map +1 -1
  397. package/dist/src/styles/defaults.d.ts +46 -26
  398. package/dist/src/styles/defaults.d.ts.map +1 -1
  399. package/dist/src/styles/defaults.js +308 -71
  400. package/dist/src/styles/defaults.js.map +1 -1
  401. package/dist/src/styles/index.d.ts +4 -3
  402. package/dist/src/styles/index.d.ts.map +1 -1
  403. package/dist/src/styles/index.js +3 -2
  404. package/dist/src/styles/index.js.map +1 -1
  405. package/dist/src/styles/internal.d.ts +1 -0
  406. package/dist/src/styles/internal.d.ts.map +1 -1
  407. package/dist/src/styles/internal.js +1 -0
  408. package/dist/src/styles/internal.js.map +1 -1
  409. package/dist/src/styles/io/generic.d.ts.map +1 -1
  410. package/dist/src/styles/io/generic.js +56 -16
  411. package/dist/src/styles/io/generic.js.map +1 -1
  412. package/dist/src/styles/io/round-trip.d.ts +56 -0
  413. package/dist/src/styles/io/round-trip.d.ts.map +1 -0
  414. package/dist/src/styles/io/round-trip.js +138 -0
  415. package/dist/src/styles/io/round-trip.js.map +1 -0
  416. package/dist/src/styles/io/writer.d.ts.map +1 -1
  417. package/dist/src/styles/io/writer.js +6 -1
  418. package/dist/src/styles/io/writer.js.map +1 -1
  419. package/dist/src/styles/notes.d.ts.map +1 -1
  420. package/dist/src/styles/notes.js +1 -0
  421. package/dist/src/styles/notes.js.map +1 -1
  422. package/dist/src/styles/plan/features.d.ts +1 -1
  423. package/dist/src/styles/plan/features.d.ts.map +1 -1
  424. package/dist/src/styles/plan/features.js +22 -2
  425. package/dist/src/styles/plan/features.js.map +1 -1
  426. package/dist/src/styles/plan/index.d.ts +1 -1
  427. package/dist/src/styles/plan/index.d.ts.map +1 -1
  428. package/dist/src/styles/plan/index.js +1 -1
  429. package/dist/src/styles/plan/index.js.map +1 -1
  430. package/dist/src/styles/plan/plan.d.ts.map +1 -1
  431. package/dist/src/styles/plan/plan.js +61 -4
  432. package/dist/src/styles/plan/plan.js.map +1 -1
  433. package/dist/src/styles/plan/resolve.d.ts +11 -0
  434. package/dist/src/styles/plan/resolve.d.ts.map +1 -1
  435. package/dist/src/styles/plan/resolve.js +40 -4
  436. package/dist/src/styles/plan/resolve.js.map +1 -1
  437. package/dist/src/styles/slots.d.ts +14 -0
  438. package/dist/src/styles/slots.d.ts.map +1 -0
  439. package/dist/src/styles/slots.js +20 -0
  440. package/dist/src/styles/slots.js.map +1 -0
  441. package/dist/src/styles/types.d.ts +622 -6
  442. package/dist/src/styles/types.d.ts.map +1 -1
  443. package/dist/src/styles/vocabulary.d.ts +3 -2
  444. package/dist/src/styles/vocabulary.d.ts.map +1 -1
  445. package/dist/src/styles/vocabulary.js +203 -0
  446. package/dist/src/styles/vocabulary.js.map +1 -1
  447. package/dist/styles.js +30 -239
  448. package/dist/styles.js.map +1 -1
  449. package/dist/xgmml.js +3 -3
  450. package/package.json +27 -7
  451. package/src/formats/cx/importer.ts +6 -1
  452. package/src/formats/cx/styles.ts +143 -9
  453. package/src/formats/cx2/importer.ts +1 -0
  454. package/src/formats/cx2/styles.ts +3 -1
  455. package/src/formats/cys/importer.ts +1 -0
  456. package/src/formats/cys/styles.ts +27 -5
  457. package/src/formats/dot/drawing.ts +799 -0
  458. package/src/formats/dot/importer.ts +120 -35
  459. package/src/formats/dot/label-places.ts +228 -0
  460. package/src/formats/dot/record.ts +336 -0
  461. package/src/formats/dot/styles.ts +1654 -153
  462. package/src/formats/gexf/dialog-metrics.ts +61 -0
  463. package/src/formats/gexf/importer.ts +50 -5
  464. package/src/formats/gexf/preview.ts +217 -0
  465. package/src/formats/gexf/schema.ts +2 -1
  466. package/src/formats/gexf/styles.ts +1099 -245
  467. package/src/formats/gml/importer.ts +291 -76
  468. package/src/formats/gml/index.ts +1 -1
  469. package/src/formats/gml/positions.ts +29 -7
  470. package/src/formats/gml/styles.ts +851 -109
  471. package/src/formats/graphml/styles-plain.ts +6 -15
  472. package/src/formats/graphml/styles-yed.ts +762 -173
  473. package/src/formats/graphml/styles-yfiles3.ts +485 -63
  474. package/src/formats/graphml/yfiles.ts +19 -6
  475. package/src/formats/json/dialect.ts +41 -5
  476. package/src/formats/json/importer.ts +59 -7
  477. package/src/formats/json/index.ts +1 -0
  478. package/src/formats/json/positions.ts +22 -5
  479. package/src/formats/json/styles.ts +2041 -185
  480. package/src/formats/pajek/draw.ts +458 -0
  481. package/src/formats/pajek/exporter.ts +81 -49
  482. package/src/formats/pajek/importer.ts +278 -103
  483. package/src/formats/pajek/index.ts +1 -0
  484. package/src/formats/pajek/styles.ts +1381 -133
  485. package/src/formats/pajek/syntax.ts +27 -2
  486. package/src/formats/xgmml/emit.ts +73 -5
  487. package/src/formats/xgmml/styles.ts +330 -71
  488. package/src/index.ts +5 -1
  489. package/src/positions/convert.ts +12 -1
  490. package/src/positions/extract.ts +55 -1
  491. package/src/positions/index.ts +1 -0
  492. package/src/positions/types.ts +60 -0
  493. package/src/sources/builtins.ts +8 -1
  494. package/src/sources/context.ts +1 -0
  495. package/src/sources/cypher/descriptor.ts +7 -1
  496. package/src/sources/cypher/index.ts +148 -18
  497. package/src/sources/cypher/params.ts +1 -1
  498. package/src/sources/cypher/query-builder.ts +33 -0
  499. package/src/sources/ids.ts +6 -0
  500. package/src/sources/params.ts +3 -0
  501. package/src/sources/rest/descriptor.ts +5 -0
  502. package/src/sources/rest/source.ts +16 -0
  503. package/src/sources/sigv4.ts +6 -4
  504. package/src/sources/sparql/descriptor.ts +67 -0
  505. package/src/sources/sparql/index.ts +356 -0
  506. package/src/sources/sparql/ntriples.ts +219 -0
  507. package/src/sources/sparql/params.ts +28 -0
  508. package/src/sources/sparql/query.ts +162 -0
  509. package/src/sources/types.ts +35 -0
  510. package/src/styles/annotations.ts +201 -27
  511. package/src/styles/canon/bends.ts +137 -0
  512. package/src/styles/canon/color-tables.ts +10 -4
  513. package/src/styles/canon/color.ts +105 -3
  514. package/src/styles/canon/enums.ts +98 -8
  515. package/src/styles/canon/graphviz.ts +71 -10
  516. package/src/styles/canon/number.ts +19 -0
  517. package/src/styles/canon/text.ts +187 -16
  518. package/src/styles/codes.ts +2 -0
  519. package/src/styles/cyjs/cascade.ts +1160 -84
  520. package/src/styles/cyjs/defaults-table.ts +3 -0
  521. package/src/styles/cyjs/emit.ts +233 -13
  522. package/src/styles/cyjs/face.ts +372 -0
  523. package/src/styles/cyjs/mappers.ts +492 -27
  524. package/src/styles/cyjs/routes.ts +432 -0
  525. package/src/styles/cytoscape/charts.ts +684 -0
  526. package/src/styles/cytoscape/emit.ts +170 -48
  527. package/src/styles/cytoscape/lexicon.ts +431 -78
  528. package/src/styles/cytoscape/mappings.ts +108 -0
  529. package/src/styles/cytoscape/resolve.ts +741 -17
  530. package/src/styles/defaults.ts +417 -108
  531. package/src/styles/index.ts +5 -0
  532. package/src/styles/internal.ts +1 -0
  533. package/src/styles/io/generic.ts +79 -23
  534. package/src/styles/io/round-trip.ts +202 -0
  535. package/src/styles/io/writer.ts +6 -1
  536. package/src/styles/notes.ts +1 -0
  537. package/src/styles/plan/features.ts +23 -2
  538. package/src/styles/plan/index.ts +1 -1
  539. package/src/styles/plan/plan.ts +69 -5
  540. package/src/styles/plan/resolve.ts +47 -4
  541. package/src/styles/slots.ts +25 -0
  542. package/src/styles/types.ts +633 -5
  543. package/src/styles/vocabulary.ts +211 -2
  544. package/dist/chunks/block-Cu22ewuS.js.map +0 -1
  545. package/dist/chunks/choose-Cdx6Enl2.js +0 -57
  546. package/dist/chunks/choose-Cdx6Enl2.js.map +0 -1
  547. package/dist/chunks/codes-CV_Bhcyi.js.map +0 -1
  548. package/dist/chunks/convert-BcQ8_jMo.js.map +0 -1
  549. package/dist/chunks/credentials-BiQsnMTb.js.map +0 -1
  550. package/dist/chunks/descriptor-BJ-W0Jd-.js.map +0 -1
  551. package/dist/chunks/emit-CD8xnY8s.js.map +0 -1
  552. package/dist/chunks/export-CZ7VRm4I.js.map +0 -1
  553. package/dist/chunks/exporter-bxxjOrDZ.js.map +0 -1
  554. package/dist/chunks/format-BMS-1Nxb.js +0 -64
  555. package/dist/chunks/format-BMS-1Nxb.js.map +0 -1
  556. package/dist/chunks/generic-CP6YD34u.js.map +0 -1
  557. package/dist/chunks/importer-B87_fmVx.js.map +0 -1
  558. package/dist/chunks/importer-CB_zV5_L.js.map +0 -1
  559. package/dist/chunks/importer-CVT-JyDE.js.map +0 -1
  560. package/dist/chunks/importer-Cyy6UseH.js.map +0 -1
  561. package/dist/chunks/importer-DPZDN40-.js.map +0 -1
  562. package/dist/chunks/importer-e3huMZbm.js.map +0 -1
  563. package/dist/chunks/lexicon-u2SI5xcx.js.map +0 -1
  564. package/dist/chunks/sigv4-LkAzsLAu.js.map +0 -1
  565. package/dist/chunks/styles-CaABMoO1.js.map +0 -1
  566. package/dist/chunks/styles-P_gmFAOi.js +0 -770
  567. package/dist/chunks/styles-P_gmFAOi.js.map +0 -1
  568. package/dist/chunks/styles-yed-Cs1nmrjn.js.map +0 -1
  569. package/dist/chunks/writer-DvHTl36J.js +0 -449
  570. package/dist/chunks/writer-DvHTl36J.js.map +0 -1
package/src/index.ts CHANGED
@@ -108,7 +108,7 @@ export {
108
108
 
109
109
  // ============================================================ network sources (experimental)
110
110
  // The contract, the load functions and credentials; each built-in source's code is its own subpath
111
- // (@graphty/graph-io/sources/ndex, /cypher, /rest), loaded on first use.
111
+ // (@graphty/graph-io/sources/ndex, /cypher, /rest, /sparql), loaded on first use.
112
112
  export {
113
113
  SOURCE_ISSUE,
114
114
  type SourceBlockedCause,
@@ -136,8 +136,10 @@ export {
136
136
  SOURCE_ENTITY_ATTR,
137
137
  SOURCE_FORMAT_PREFIX,
138
138
  SOURCE_STUB_ATTR,
139
+ SPARQL_SOURCE_ID,
139
140
  } from "./sources/ids.js";
140
141
  export { type SourceParamsMap } from "./sources/params.js";
142
+ export { sha256Hex } from "./sources/sigv4.js";
141
143
  export {
142
144
  type Recording,
143
145
  recordingFrom,
@@ -185,6 +187,7 @@ export {
185
187
  type SourceRuntime,
186
188
  type SourceRuntimeReason,
187
189
  type SourceSample,
190
+ type SourceTotal,
188
191
  type SourceValidators,
189
192
  } from "./sources/types.js";
190
193
 
@@ -281,6 +284,7 @@ export {
281
284
  type JsonImportOptions,
282
285
  type JsonShapeMeta,
283
286
  jsonShapeOf,
287
+ sniffJsonDialect,
284
288
  } from "./formats/json/index.js";
285
289
  export {
286
290
  exportNeo4jFiles,
@@ -16,6 +16,15 @@ export function flipY(y: number): number {
16
16
  return y === 0 ? 0 : -y;
17
17
  }
18
18
 
19
+ /**
20
+ * How much longer a unit of y is than a unit of x, for a program that stretches its axes apart.
21
+ * @param extra - how the file spells its coordinates
22
+ * @returns `pxPerUnitY / pxPerUnit`, 1 when either is absent
23
+ */
24
+ function yStretch(extra: PositionColumnExtra): number {
25
+ return extra.pxPerUnit === undefined || extra.pxPerUnitY === undefined ? 1 : extra.pxPerUnitY / extra.pxPerUnit;
26
+ }
27
+
19
28
  /**
20
29
  * One coordinate from a file's spelling into the neutral convention, in place.
21
30
  * @param p - x, y, z as the file wrote them; becomes the node's center, y up
@@ -29,6 +38,7 @@ export function toNeutral(
29
38
  size: readonly [number, number] | null,
30
39
  realZ: boolean,
31
40
  ): void {
41
+ p[1] *= yStretch(extra);
32
42
  if (extra.anchor === "top-left" && size !== null) {
33
43
  p[0] += size[0] / 2;
34
44
  p[1] += extra.yAxis === "down" ? size[1] / 2 : -size[1] / 2;
@@ -60,8 +70,9 @@ export function toFilePositions(
60
70
  ): Float64Array {
61
71
  const out = new Float64Array(coords.length);
62
72
  const down = extra.yAxis === "down";
73
+ const stretch = yStretch(extra);
63
74
  for (let i = 0; i < coords.length; i += 3) {
64
- let y = coords[i + 1];
75
+ let y = coords[i + 1] / stretch;
65
76
  let z = coords[i + 2];
66
77
  if (down) {
67
78
  y = flipY(y);
@@ -89,6 +89,11 @@ export function extractPositions(
89
89
  const coords = readRows(n, spelling, notes);
90
90
  signal?.throwIfAborted();
91
91
  const containers = containersOf(snapshot);
92
+ if (spelling.extra.containersFollowChildren === true) {
93
+ for (const row of containers) {
94
+ coords.values.fill(Number.NaN, 3 * row, 3 * row + 3);
95
+ }
96
+ }
92
97
  const groups = applyGroups(spelling, coords);
93
98
  collectGroups(spelling, coords, containers, groups);
94
99
  const { placed, total } = countPlaced(coords, containers, notes);
@@ -104,6 +109,7 @@ export function extractPositions(
104
109
  },
105
110
  units: spelling.extra.units ?? "file",
106
111
  ...(spelling.extra.pxPerUnit === undefined ? {} : { pxPerUnit: spelling.extra.pxPerUnit }),
112
+ ...(spelling.extra.viewerFit === undefined ? {} : { viewerFit: spelling.extra.viewerFit }),
107
113
  medianNodeSize: spelling.medianNodeSize ?? medianSize(spelling.size, n, containers),
108
114
  dims: coords.realZ ? 3 : 2,
109
115
  coords: coords.values,
@@ -132,12 +138,35 @@ function spellingOf(importer: GraphImporter, snapshot: GraphSnapshot, signal: Ab
132
138
  }
133
139
  const column = hook?.column === undefined ? snapshot.nodes.byRole("position") : snapshot.nodes.get(hook.column);
134
140
  if (column === null || column.meta.components < 2) {
135
- return null;
141
+ return hook?.unplacedCircle === undefined ? null : circleSpelling(snapshot, hook);
136
142
  }
137
143
  const extra = { ...extraOf(column.meta.extra), ...extraOf(hook ?? {}) };
138
144
  return { read: vectorReader(column), size: sizeReader(snapshot, extra), extra, ...hookFields(hook) };
139
145
  }
140
146
 
147
+ /**
148
+ * The spelling of a file that places no node, whose program puts them round a circle (`unplacedCircle`).
149
+ * @param snapshot - the graph
150
+ * @param hook - the hook's answer, with its circle
151
+ * @returns the spelling
152
+ */
153
+ function circleSpelling(snapshot: GraphSnapshot, hook: ImporterPositions): Spelling {
154
+ const circle = hook.unplacedCircle;
155
+ const n = snapshot.nodeCount;
156
+ const read: RowReader = (row, out) => {
157
+ if (circle === undefined || n === 0) {
158
+ return false;
159
+ }
160
+ const a = ((circle.startDegrees + (circle.direction * 360 * row) / n) * Math.PI) / 180;
161
+ out[0] = circle.center[0] + circle.radius * Math.cos(a);
162
+ out[1] = circle.center[1] + circle.radius * Math.sin(a);
163
+ out[2] = 0;
164
+ return true;
165
+ };
166
+ const extra = { ...extraOf(hook), sourceDims: 2 } as const;
167
+ return { read, size: sizeReader(snapshot, extra), extra, ...hookFields(hook) };
168
+ }
169
+
141
170
  /**
142
171
  * The spelling of the simple hook form: plain x / y (/ z) columns.
143
172
  * @param snapshot - the graph
@@ -211,8 +240,15 @@ function extraOf(source: object): PositionColumnExtra {
211
240
  pick("width", (v) => typeof v === "string");
212
241
  pick("height", (v) => typeof v === "string");
213
242
  pick("pxPerUnit", (v) => typeof v === "number" && Number.isFinite(v) && v > 0);
243
+ pick("pxPerUnitY", (v) => typeof v === "number" && Number.isFinite(v) && v > 0);
214
244
  pick("zOrigin", (v) => typeof v === "number" && Number.isFinite(v));
215
245
  pick("zeroUnplaced", (v) => typeof v === "boolean");
246
+ pick("originUnplaced", (v) => typeof v === "boolean");
247
+ pick("containersFollowChildren", (v) => typeof v === "boolean");
248
+ const fit = extra.viewerFit as Readonly<Record<string, unknown>> | null | undefined;
249
+ if (typeof fit?.padding === "number" && Number.isFinite(fit.padding) && fit.padding >= 0) {
250
+ out.viewerFit = { padding: fit.padding };
251
+ }
216
252
  return out;
217
253
  }
218
254
 
@@ -247,11 +283,29 @@ function readRows(n: number, spelling: Spelling, notes: NoteCollector<PositionNo
247
283
  if (spelling.extra.zeroUnplaced === true) {
248
284
  dropZeroPile(values);
249
285
  }
286
+ if (spelling.extra.originUnplaced === true) {
287
+ placeUnplacedAtOrigin(values);
288
+ }
250
289
  const realZ = spelling.extra.sourceDims === 3 && !constantZ(values);
251
290
  convertRows(values, spelling.extra, spelling.size, realZ, notes);
252
291
  return { values, realZ };
253
292
  }
254
293
 
294
+ /**
295
+ * Put every unplaced row at the origin, when at least one row is placed.
296
+ * @param values - the coordinates, three per row; NaN rows are unplaced
297
+ */
298
+ function placeUnplacedAtOrigin(values: Float64Array): void {
299
+ if (!values.some((v) => !Number.isNaN(v))) {
300
+ return;
301
+ }
302
+ for (let i = 0; i < values.length; i += 3) {
303
+ if (Number.isNaN(values[i])) {
304
+ values.fill(0, i, i + 3);
305
+ }
306
+ }
307
+ }
308
+
255
309
  /**
256
310
  * Convert every placed row in place.
257
311
  * @param values - the raw coordinates
@@ -19,5 +19,6 @@ export type {
19
19
  PositionColumnExtra,
20
20
  PositionNote,
21
21
  PositionReadContext,
22
+ ViewerFit,
22
23
  YAxis,
23
24
  } from "./types.js";
@@ -41,6 +41,19 @@ export interface PositionColumnExtra {
41
41
  * the same unit as the file's px style lengths; the coordinates themselves stay as written.
42
42
  */
43
43
  readonly pxPerUnit?: number;
44
+ /**
45
+ * How many px one unit of y is, when the program that draws the file stretches its axes apart
46
+ * (Pajek fits the file's 0..1 square to its Draw window, x across the width and y down the
47
+ * height); absent when y is `pxPerUnit` like x. `extractPositions()` returns y in x's unit.
48
+ */
49
+ readonly pxPerUnitY?: number;
50
+ /**
51
+ * Set when the coordinates have no fixed length: the program that draws the file fits their
52
+ * bounding box into its canvas, `padding` px in from each side, and draws label sizes in the
53
+ * canvas's px rather than in the coordinates' unit (sigma.js). Absent when the coordinates
54
+ * keep their own length.
55
+ */
56
+ readonly viewerFit?: ViewerFit;
44
57
  /** How many coordinates the file wrote per node: 2, or 3 when it stored a z. */
45
58
  readonly sourceDims?: 2 | 3;
46
59
  /** Which way y grows; "down" is flipped to y up. */
@@ -58,6 +71,30 @@ export interface PositionColumnExtra {
58
71
  * rows are placed, a (0, 0) shared by two or more rows counts as unplaced.
59
72
  */
60
73
  readonly zeroUnplaced?: boolean;
74
+ /**
75
+ * The program that draws the file puts a node the file gives no position at the origin, (0, 0, 0) as written,
76
+ * when other nodes are placed (Gephi), rather than leaving it for a layout to place.
77
+ */
78
+ readonly originUnplaced?: boolean;
79
+ /**
80
+ * The program that draws the file draws a container node (one other nodes name as their
81
+ * parent) around its children, wherever the container's own stored coordinate says: Cytoscape.js
82
+ * computes a compound node's position and size from its children's. A container's stored
83
+ * coordinate is then not read, and it has no position here unless the file stores its box.
84
+ */
85
+ readonly containersFollowChildren?: boolean;
86
+ }
87
+
88
+ /**
89
+ * How the program that draws a file fits coordinates that have no fixed length into its canvas.
90
+ * @category Positions
91
+ */
92
+ export interface ViewerFit {
93
+ /**
94
+ * The px the fitted bounding box keeps from each end of the canvas's smaller side; along the
95
+ * longer side the room is that side's share of the same fraction (sigma.js's `stagePadding`).
96
+ */
97
+ readonly padding: number;
61
98
  }
62
99
 
63
100
  /**
@@ -104,6 +141,22 @@ export interface ImporterPositions extends PositionColumnExtra {
104
141
  readonly medianNodeSize?: number | null;
105
142
  /** The tool that wrote the file, when the importer knows it better than `meta.creator`. */
106
143
  readonly tool?: GraphTool | null;
144
+ /**
145
+ * Where the program that draws the file puts its nodes when the file places none: evenly round a circle in node
146
+ * order, the first at `startDegrees`, each next one further round in `direction` (1: the angle grows, -1: it
147
+ * shrinks), in the file's own coordinates as the rest of this answer spells them (Pajek: center 0.5, 0.5, radius
148
+ * 0.4, the first vertex on the left). Absent, such a file has no positions.
149
+ */
150
+ readonly unplacedCircle?: {
151
+ /** The circle's center, x and y. */
152
+ readonly center: readonly [number, number];
153
+ /** Its radius. */
154
+ readonly radius: number;
155
+ /** The angle of the first node, in degrees. */
156
+ readonly startDegrees: number;
157
+ /** Which way round the next nodes go: 1 the angle grows, -1 it shrinks. */
158
+ readonly direction: 1 | -1;
159
+ };
107
160
  }
108
161
 
109
162
  /**
@@ -186,6 +239,13 @@ export interface FilePositions {
186
239
  * it with the file's px style lengths.
187
240
  */
188
241
  readonly pxPerUnit?: number;
242
+ /**
243
+ * Set when the coordinates have no fixed length: the program that draws the file fits their
244
+ * bounding box into its canvas, `padding` px in from each side, and draws label sizes in the
245
+ * canvas's px (sigma.js). A label of `s` px is then `s / k` units, where k is the px per unit of
246
+ * that fit on the canvas it is drawn on. Absent otherwise.
247
+ */
248
+ readonly viewerFit?: ViewerFit;
189
249
  /** The median node diameter, in `units`, when the file stores node sizes; else null. */
190
250
  readonly medianNodeSize: number | null;
191
251
  /** 3 when the nodes differ in z, else 2 (z is then 0). */
@@ -11,13 +11,15 @@ import {
11
11
  NEPTUNE_SOURCE_ID,
12
12
  OPENALEX_SOURCE_ID,
13
13
  REST_SOURCE_ID,
14
+ SPARQL_SOURCE_ID,
14
15
  } from "./ids.js";
15
16
  import { NDEX_DESCRIPTOR } from "./ndex/descriptor.js";
16
17
  import { OPENALEX_DESCRIPTOR, REST_DESCRIPTOR } from "./rest/descriptor.js";
18
+ import { SPARQL_DESCRIPTOR } from "./sparql/descriptor.js";
17
19
  import { type LazySource } from "./types.js";
18
20
 
19
21
  /**
20
- * The six built-in sources, each loading its subpath on first use.
22
+ * The seven built-in sources, each loading its subpath on first use.
21
23
  * @returns the lazy sources, in catalog order
22
24
  */
23
25
  export function builtinSources(): readonly LazySource[] {
@@ -52,5 +54,10 @@ export function builtinSources(): readonly LazySource[] {
52
54
  descriptor: OPENALEX_DESCRIPTOR,
53
55
  load: async () => (await import("./rest/index.js")).openalexSource,
54
56
  },
57
+ {
58
+ id: SPARQL_SOURCE_ID,
59
+ descriptor: SPARQL_DESCRIPTOR,
60
+ load: async () => (await import("./sparql/index.js")).sparqlSource,
61
+ },
55
62
  ];
56
63
  }
@@ -835,6 +835,7 @@ class SourceFetcher {
835
835
  ...(finish?.server === undefined ? {} : { server: finish.server }),
836
836
  ...(finish?.budget === undefined ? {} : { budget: finish.budget }),
837
837
  ...(finish?.validators === undefined ? {} : { validators: finish.validators }),
838
+ ...(finish?.total === undefined ? {} : { total: finish.total }),
838
839
  });
839
840
  }
840
841
  }
@@ -3,7 +3,7 @@
3
3
  * the sources' code.
4
4
  */
5
5
 
6
- import { type SourceDescriptor, type SourceParamDescriptor } from "../types.js";
6
+ import { type SourceDescriptor, type SourceFeature, type SourceParamDescriptor } from "../types.js";
7
7
 
8
8
  /** The parameters every Cypher source shares. */
9
9
  const CYPHER_PARAMS: readonly SourceParamDescriptor[] = [
@@ -38,6 +38,9 @@ const CYPHER_PARAMS: readonly SourceParamDescriptor[] = [
38
38
  { name: "pageSize", plainName: "Page size", type: "integer", default: 1000, min: 1, max: 100000, advanced: true },
39
39
  ];
40
40
 
41
+ /** What every Cypher source can do: expand, probe, validate, and page a capped load. */
42
+ const CYPHER_FEATURES: readonly SourceFeature[] = ["expand", "probe", "validate", "page"];
43
+
41
44
  /** The transport parameter of the generic source. */
42
45
  const TRANSPORT_PARAM: SourceParamDescriptor = {
43
46
  name: "transport",
@@ -61,6 +64,7 @@ export const CYPHER_DESCRIPTOR: SourceDescriptor = Object.freeze({
61
64
  version: 1,
62
65
  auth: ["basic", "bearer", "aws-sigv4"],
63
66
  authRequired: "optional",
67
+ features: CYPHER_FEATURES,
64
68
  params: [...CYPHER_PARAMS, TRANSPORT_PARAM],
65
69
  });
66
70
 
@@ -74,6 +78,7 @@ export const NEO4J_DESCRIPTOR: SourceDescriptor = Object.freeze({
74
78
  version: 1,
75
79
  auth: ["basic", "bearer"],
76
80
  authRequired: "optional",
81
+ features: CYPHER_FEATURES,
77
82
  params: [
78
83
  ...CYPHER_PARAMS,
79
84
  {
@@ -112,6 +117,7 @@ export const NEPTUNE_DESCRIPTOR: SourceDescriptor = Object.freeze({
112
117
  version: 1,
113
118
  auth: ["aws-sigv4"],
114
119
  authRequired: "optional",
120
+ features: CYPHER_FEATURES,
115
121
  params: [
116
122
  ...CYPHER_PARAMS,
117
123
  {
@@ -25,10 +25,11 @@ import {
25
25
  type SourceDescriptor,
26
26
  type SourceFreshness,
27
27
  type SourceProbe,
28
+ type SourceTotal,
28
29
  type SourceValidators,
29
30
  } from "../types.js";
30
31
  import { CYPHER_DESCRIPTOR, NEO4J_DESCRIPTOR, NEPTUNE_DESCRIPTOR } from "./descriptor.js";
31
- import { canonicalRows, Collector, compareText, requireGraph, writeCollected } from "./flatten.js";
32
+ import { canonicalRows, Collector, compareText, type QueryResult, requireGraph, writeCollected } from "./flatten.js";
32
33
  import { type CypherParams } from "./params.js";
33
34
  import { type CypherProfile, neo4jProfile, neptuneProfile, serverFacts } from "./profiles.js";
34
35
  import {
@@ -36,12 +37,14 @@ import {
36
37
  counts,
37
38
  DEFAULT_PAGE_SIZE,
38
39
  edgePage,
40
+ edgesAmong,
39
41
  MAX_DEPTH,
40
42
  MAX_PAGE_SIZE,
41
43
  neighborhood,
42
44
  nodePage,
43
45
  type QueryFilters,
44
46
  quoted,
47
+ storeCount,
45
48
  } from "./query-builder.js";
46
49
  import { boltTransport } from "./transports/bolt.js";
47
50
  import { neptuneAnalyticsTransport } from "./transports/neptune-analytics.js";
@@ -77,6 +80,20 @@ interface Page {
77
80
  /** The directions an expansion may follow. */
78
81
  const DIRECTIONS: ReadonlySet<string> = new Set(["out", "in", "both"]);
79
82
 
83
+ /**
84
+ * A query without the semicolons it ends with, so it can sit inside `CALL { }`. A loop, not
85
+ * `/;+$/`, which backtracks over every run of semicolons that is not at the end.
86
+ * @param query - the trimmed query
87
+ * @returns the query
88
+ */
89
+ function withoutTrailingSemicolons(query: string): string {
90
+ let end = query.length;
91
+ while (end > 0 && query[end - 1] === ";") {
92
+ end--;
93
+ }
94
+ return query.slice(0, end);
95
+ }
96
+
80
97
  /**
81
98
  * A list parameter: an array, or one value. A string is one item, never split, since an id or a
82
99
  * label may hold any character.
@@ -124,6 +141,8 @@ class Reader {
124
141
  private known: CypherProfile | null = null;
125
142
  private degree = true;
126
143
  readonly filters: QueryFilters;
144
+ /** What the source holds for this load, when a count ran. */
145
+ counted: SourceTotal | undefined;
127
146
  /** The raw id property, for the node ids. */
128
147
  readonly idProperty: string | null;
129
148
 
@@ -195,9 +214,10 @@ class Reader {
195
214
  /**
196
215
  * The pages of a read, as `mode` asks.
197
216
  * @param cursor - where to resume
217
+ * @param counting - whether a first page of mode "all" may count what the source holds
198
218
  * @yields one page at a time
199
219
  */
200
- async *pages(cursor: SourceCursor | null): AsyncGenerator<Page> {
220
+ async *pages(cursor: SourceCursor | null, counting = true): AsyncGenerator<Page> {
201
221
  const { params, ctx } = this;
202
222
  const { report } = ctx;
203
223
  const mode = params.mode ?? (typeof params.query === "string" && params.query !== "" ? "query" : "all");
@@ -205,11 +225,7 @@ class Reader {
205
225
  if (typeof params.query !== "string" || params.query.trim() === "") {
206
226
  failOn(report, "E_SOURCE_PARAM", "mode query needs a query", { name: "query", reason: "required" });
207
227
  }
208
- const result = await this.transport.run(params.query, params.parameters ?? {});
209
- const collected = new Collector();
210
- collected.add(result, false);
211
- requireGraph(result, collected, report);
212
- yield { collected, next: null };
228
+ yield await this.userQuery(params.query, cursor);
213
229
  return;
214
230
  }
215
231
  const profile = await this.profile();
@@ -230,7 +246,47 @@ class Reader {
230
246
  yield { collected, next: null };
231
247
  return;
232
248
  }
233
- yield* this.everything(profile, cursor);
249
+ yield* this.everything(profile, cursor, counting);
250
+ }
251
+
252
+ /**
253
+ * Mode "query": the reader's own query, as written. With a node cap (or a cursor from a capped
254
+ * run) the server returns at most that many rows (`CALL { query } RETURN * LIMIT n`), and a full
255
+ * result hands back a cursor that runs the query again with twice the rows, for the caller to
256
+ * merge. A server that refuses the wrapper runs the query uncapped.
257
+ * @param query - the query
258
+ * @param cursor - where to resume: `{ rows }` from an earlier capped run
259
+ * @returns the one page
260
+ */
261
+ private async userQuery(query: string, cursor: SourceCursor | null): Promise<Page> {
262
+ const { params, ctx } = this;
263
+ const parameters = params.parameters ?? {};
264
+ const asked = cursor?.rows ?? ctx.limits.maxNodes;
265
+ const rows =
266
+ asked === undefined || asked === null
267
+ ? null
268
+ : Number(checkedInteger(asked, "maxNodes", 1, Number.MAX_SAFE_INTEGER, ctx.report));
269
+ let result: QueryResult;
270
+ let capped = rows !== null;
271
+ try {
272
+ result = await this.transport.run(
273
+ rows === null
274
+ ? query
275
+ : `CALL {\n${withoutTrailingSemicolons(query.trim())}\n}\nRETURN * LIMIT ${String(rows)}`,
276
+ parameters,
277
+ );
278
+ } catch (err) {
279
+ if (!capped || !(err instanceof ImportError) || err.issue?.code !== SOURCE_ISSUE.E_SOURCE_QUERY) {
280
+ throw err;
281
+ }
282
+ capped = false;
283
+ result = await this.transport.run(query, parameters);
284
+ }
285
+ const collected = new Collector();
286
+ collected.add(result, false);
287
+ requireGraph(result, collected, ctx.report);
288
+ const full = capped && rows !== null && result.rows.length >= rows;
289
+ return { collected, next: full ? { rows: rows * 2 } : null };
234
290
  }
235
291
 
236
292
  /**
@@ -238,14 +294,33 @@ class Reader {
238
294
  * id expression (never SKIP), so a page is stable under unrelated writes.
239
295
  * @param profile - the server's profile
240
296
  * @param cursor - where to resume
297
+ * @param counting - whether a first page may count what the source holds
241
298
  * @yields one page at a time
242
299
  */
243
- private async *everything(profile: CypherProfile, cursor: SourceCursor | null): AsyncGenerator<Page> {
300
+ private async *everything(
301
+ profile: CypherProfile,
302
+ cursor: SourceCursor | null,
303
+ counting: boolean,
304
+ ): AsyncGenerator<Page> {
244
305
  const { params, ctx } = this;
245
306
  const size = checkedInteger(params.pageSize ?? DEFAULT_PAGE_SIZE, "pageSize", 1, MAX_PAGE_SIZE, ctx.report);
307
+ if (cursor === null && counting) {
308
+ this.counted = await this.count(profile);
309
+ }
310
+ const cap = ctx.limits.maxNodes;
311
+ if (cap !== undefined && cursor?.phase !== "edges") {
312
+ const capped = Number(checkedInteger(cap, "maxNodes", 1, Number.MAX_SAFE_INTEGER, ctx.report));
313
+ yield* this.cappedNodes(profile, cursor, Math.min(Number(size), capped));
314
+ return;
315
+ }
316
+
246
317
  let phase: "nodes" | "edges" = cursor?.phase === "edges" ? "edges" : "nodes";
247
318
  let after: string | number | boolean | null = cursor?.after ?? null;
248
- const total = params.countFirst === true && cursor === null ? await this.total() : undefined;
319
+ const { counted } = this;
320
+ const total =
321
+ params.countFirst === true && counted !== undefined
322
+ ? (counted.nodes ?? 0) + (counted.edges ?? 0)
323
+ : undefined;
249
324
  for (;;) {
250
325
  const nodes = phase === "nodes";
251
326
  const { collected, rows, fields } = await this.generated(
@@ -268,13 +343,67 @@ class Reader {
268
343
  }
269
344
 
270
345
  /**
271
- * How many nodes and relationships the filters match, for progress.
272
- * @returns the count
346
+ * Mode "all" under a node cap: pages of at most the cap's nodes, each with the relationships
347
+ * among the nodes loaded so far, so a capped load stops at its cap with its edges, and its
348
+ * next page (`data.more`) continues by key.
349
+ * @param profile - the server's profile
350
+ * @param cursor - where to resume
351
+ * @param size - the page size
352
+ * @yields one page at a time
353
+ */
354
+ private async *cappedNodes(
355
+ profile: CypherProfile,
356
+ cursor: SourceCursor | null,
357
+ size: number,
358
+ ): AsyncGenerator<Page> {
359
+ let after: string | number | boolean | null = cursor?.after ?? null;
360
+ for (;;) {
361
+ const { collected, rows, fields } = await this.generated(
362
+ (d) => nodePage(profile, this.filters, String(size), after !== null, d),
363
+ after === null ? {} : { after },
364
+ );
365
+ const last = rows.at(-1)?.[fields.indexOf("key")];
366
+ const key = typeof last === "string" || typeof last === "number" ? last : null;
367
+ if (key !== null) {
368
+ const among = await this.transport.run(edgesAmong(profile, this.filters, after !== null), {
369
+ last: key,
370
+ ...(after === null ? {} : { after }),
371
+ });
372
+ collected.add(among, false);
373
+ }
374
+ const next = rows.length >= size && key !== null ? { phase: "nodes", after: key } : null;
375
+ yield { collected, next };
376
+ if (next === null) {
377
+ return;
378
+ }
379
+ after = key;
380
+ }
381
+ }
382
+
383
+ /**
384
+ * What a first page of mode "all" counts: with `countFirst`, the nodes and relationships the
385
+ * filters match (for progress too); else, on Neo4j with at most one label and the server's
386
+ * ids, the nodes from the count store; else nothing.
387
+ * @param profile - the server's profile
388
+ * @returns the count, or undefined
273
389
  */
274
- private async total(): Promise<number> {
275
- const [n, r] = counts(this.filters);
276
- const [a, b] = await Promise.all([this.transport.run(n, {}), this.transport.run(r, {})]);
277
- return Number(a.rows[0]?.[0] ?? 0) + Number(b.rows[0]?.[0] ?? 0);
390
+ private async count(profile: CypherProfile): Promise<SourceTotal | undefined> {
391
+ // A count is a non-negative integer; anything else a server answers is no count.
392
+ const first = async (statement: string): Promise<number | undefined> => {
393
+ const c = Number((await this.transport.run(statement, {})).rows[0]?.[0]);
394
+ return Number.isSafeInteger(c) && c >= 0 ? c : undefined;
395
+ };
396
+ const { labels, idProperty } = this.filters;
397
+ if (this.params.countFirst === true) {
398
+ const [n, r] = counts(this.filters);
399
+ const [nodes, edges] = await Promise.all([first(n), first(r)]);
400
+ return { ...(nodes === undefined ? {} : { nodes }), ...(edges === undefined ? {} : { edges }) };
401
+ }
402
+ if (profile.name !== "neo4j" || labels.length > 1 || idProperty !== null) {
403
+ return undefined;
404
+ }
405
+ const nodes = await first(storeCount(labels[0]));
406
+ return nodes === undefined ? undefined : { nodes };
278
407
  }
279
408
 
280
409
  /**
@@ -392,7 +521,8 @@ function cypher(preset: Preset): GraphSource<CypherParams> {
392
521
  break;
393
522
  }
394
523
  }
395
- return ctx.finish({ next, ...(await reader.facts(lines)) });
524
+ const total = reader.counted === undefined ? {} : { total: reader.counted };
525
+ return ctx.finish({ next, ...total, ...(await reader.facts(lines)) });
396
526
  }),
397
527
  expand: (request, sink, ctx) =>
398
528
  withReader(request.params, ctx, preset, (reader) => expand(reader, request, sink)),
@@ -404,7 +534,7 @@ function cypher(preset: Preset): GraphSource<CypherParams> {
404
534
  validate: (params, seen, ctx) =>
405
535
  withReader(params, ctx, preset, async (reader): Promise<SourceFreshness> => {
406
536
  const lines: string[] = [];
407
- for await (const page of reader.pages(null)) {
537
+ for await (const page of reader.pages(null, false)) {
408
538
  lines.push(...canonicalRows(page.collected, reader.idProperty));
409
539
  }
410
540
  const { validators } = await reader.facts(lines);
@@ -36,6 +36,6 @@ export interface CypherParams {
36
36
  readonly long?: "f64" | "string" | undefined;
37
37
  /** Run a count first, for a progress total. @defaultValue false */
38
38
  readonly countFirst?: boolean | undefined;
39
- /** Rows per page of mode "all", 1 to 100000. A load stops between pages, so a cap overshoots by at most one page. @defaultValue 1000 */
39
+ /** Rows per page of mode "all", 1 to 100000. Under a node cap a page holds at most the cap's nodes, with the relationships among the nodes loaded so far. @defaultValue 1000 */
40
40
  readonly pageSize?: number | undefined;
41
41
  }
@@ -215,6 +215,28 @@ export function edgePage(profile: CypherProfile, filters: QueryFilters, pageSize
215
215
  .join(" ");
216
216
  }
217
217
 
218
+ /**
219
+ * The relationships among the nodes a capped mode "all" has loaded: both ends at or before the
220
+ * node page's last key `$last`, and, after the first page, one end past the previous page's last
221
+ * key `$after`, so each relationship arrives with the page that loads its later end.
222
+ * @param profile - the server's profile
223
+ * @param filters - the filters
224
+ * @param after - whether earlier pages were loaded
225
+ * @returns the statement; it reads `$last` and `$after`
226
+ */
227
+ export function edgesAmong(profile: CypherProfile, filters: QueryFilters, after: boolean): string {
228
+ const where = [nodePredicate("a", filters), nodePredicate("b", filters)].filter((p) => p !== null);
229
+ return [
230
+ `MATCH (a)-[r${typesPattern(filters)}]->(b)`,
231
+ where.length === 0 ? null : `WHERE ${where.join(" AND ")}`,
232
+ `WITH a, r, b, ${idExpression("a", profile, filters)} AS ka, ${idExpression("b", profile, filters)} AS kb`,
233
+ `WHERE ka <= $last AND kb <= $last${after ? " AND (ka > $after OR kb > $after)" : ""}`,
234
+ "RETURN a, r, b",
235
+ ]
236
+ .filter((l) => l !== null)
237
+ .join(" ");
238
+ }
239
+
218
240
  /** How far a neighborhood reaches. */
219
241
  interface NeighborhoodShape {
220
242
  /** The checked depth, as text. */
@@ -292,3 +314,14 @@ export function counts(filters: QueryFilters): readonly [string, string] {
292
314
  `MATCH (a)-[r${typesPattern(filters)}]->(b)${whereClause(where.length === 0 ? null : where.join(" AND "))} RETURN count(r) AS c`,
293
315
  ];
294
316
  }
317
+
318
+ /**
319
+ * The node count of a mode "all" load with at most one label and the server's ids: a pattern
320
+ * Neo4j answers from its count store in one cheap lookup, whatever the graph's size.
321
+ * @param label - the quoted label, or undefined for every node
322
+ * @returns the statement
323
+ */
324
+ export function storeCount(label: string | undefined): string {
325
+ const pattern = label === undefined ? "n" : `n:${label}`;
326
+ return `MATCH (${pattern}) RETURN count(n) AS c`;
327
+ }
@@ -42,6 +42,12 @@ export const REST_SOURCE_ID = "rest";
42
42
  */
43
43
  export const OPENALEX_SOURCE_ID = "openalex";
44
44
 
45
+ /**
46
+ * The SPARQL source, for any SPARQL 1.1 endpoint. Experimental.
47
+ * @category Network sources
48
+ */
49
+ export const SPARQL_SOURCE_ID = "sparql";
50
+
45
51
  /**
46
52
  * The prefix of the reserved attribute namespace sources and graphty-element write facts under.
47
53
  * @category Network sources