@graphty/graph-io 0.3.48 → 0.3.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (600) hide show
  1. package/dist/chunks/{approximations-C2riR4NT.js → approximations-BRXsll0T.js} +2 -2
  2. package/dist/chunks/{approximations-C2riR4NT.js.map → approximations-BRXsll0T.js.map} +1 -1
  3. package/dist/chunks/bends-BGXjv_U4.js +129 -0
  4. package/dist/chunks/bends-BGXjv_U4.js.map +1 -0
  5. package/dist/chunks/{block-Cu22ewuS.js → block-yl0f_qLO.js} +931 -164
  6. package/dist/chunks/block-yl0f_qLO.js.map +1 -0
  7. package/dist/chunks/choose-CczZJaX_.js +717 -0
  8. package/dist/chunks/choose-CczZJaX_.js.map +1 -0
  9. package/dist/chunks/{codes-CV_Bhcyi.js → codes-BE2xir2k.js} +6 -2
  10. package/dist/chunks/codes-BE2xir2k.js.map +1 -0
  11. package/dist/chunks/{constants-D0LqcsLJ.js → constants-CKkYLPtt.js} +2 -2
  12. package/dist/chunks/{constants-D0LqcsLJ.js.map → constants-CKkYLPtt.js.map} +1 -1
  13. package/dist/chunks/{context-cgmmOxZ2.js → context-DizmppHy.js} +5 -4
  14. package/dist/chunks/{context-cgmmOxZ2.js.map → context-DizmppHy.js.map} +1 -1
  15. package/dist/chunks/{convert-BcQ8_jMo.js → convert-Ct2zelbQ.js} +7 -2
  16. package/dist/chunks/convert-Ct2zelbQ.js.map +1 -0
  17. package/dist/chunks/{credentials-BiQsnMTb.js → credentials-CmvJXYeH.js} +67 -16
  18. package/dist/chunks/credentials-CmvJXYeH.js.map +1 -0
  19. package/dist/chunks/{cx-export-BEeF6ymo.js → cx-export-Bt6NoqTQ.js} +3 -3
  20. package/dist/chunks/{cx-export-BEeF6ymo.js.map → cx-export-Bt6NoqTQ.js.map} +1 -1
  21. package/dist/chunks/descriptor-B28U25x4.js +60 -0
  22. package/dist/chunks/descriptor-B28U25x4.js.map +1 -0
  23. package/dist/chunks/{descriptor-BJ-W0Jd-.js → descriptor-Dhez_Cew.js} +11 -2
  24. package/dist/chunks/descriptor-Dhez_Cew.js.map +1 -0
  25. package/dist/chunks/{emit-CD8xnY8s.js → emit-7Jkpg0yd.js} +1788 -133
  26. package/dist/chunks/emit-7Jkpg0yd.js.map +1 -0
  27. package/dist/chunks/{escape-DH2Egt-l.js → escape-CuCIzNMB.js} +8 -8
  28. package/dist/chunks/{escape-DH2Egt-l.js.map → escape-CuCIzNMB.js.map} +1 -1
  29. package/dist/chunks/{export-CZ7VRm4I.js → export-Cha4dRFz.js} +45 -387
  30. package/dist/chunks/export-Cha4dRFz.js.map +1 -0
  31. package/dist/chunks/{exporter-ChjL5fmP.js → exporter-1Ajud15J.js} +9 -8
  32. package/dist/chunks/{exporter-ChjL5fmP.js.map → exporter-1Ajud15J.js.map} +1 -1
  33. package/dist/chunks/{exporter-BIdaoIgh.js → exporter-B6yvL3wy.js} +7 -7
  34. package/dist/chunks/{exporter-BIdaoIgh.js.map → exporter-B6yvL3wy.js.map} +1 -1
  35. package/dist/chunks/{exporter-Dcw7Ldtq.js → exporter-BP6otMO6.js} +6 -6
  36. package/dist/chunks/{exporter-Dcw7Ldtq.js.map → exporter-BP6otMO6.js.map} +1 -1
  37. package/dist/chunks/{exporter-DtVU80Fa.js → exporter-CA5q8ROP.js} +9 -8
  38. package/dist/chunks/{exporter-DtVU80Fa.js.map → exporter-CA5q8ROP.js.map} +1 -1
  39. package/dist/chunks/{exporter-bxxjOrDZ.js → exporter-CQQZFJ2v.js} +1284 -156
  40. package/dist/chunks/exporter-CQQZFJ2v.js.map +1 -0
  41. package/dist/chunks/format-BXiAb-1h.js +408 -0
  42. package/dist/chunks/format-BXiAb-1h.js.map +1 -0
  43. package/dist/chunks/{generic-CP6YD34u.js → generic-Dc21MAdg.js} +387 -31
  44. package/dist/chunks/generic-Dc21MAdg.js.map +1 -0
  45. package/dist/chunks/{importer-B87_fmVx.js → importer-C6NVpCXp.js} +327 -84
  46. package/dist/chunks/importer-C6NVpCXp.js.map +1 -0
  47. package/dist/chunks/{importer-DPZDN40-.js → importer-CKFe4q54.js} +25 -17
  48. package/dist/chunks/importer-CKFe4q54.js.map +1 -0
  49. package/dist/chunks/{importer-Bji2MeWr.js → importer-CKbUbsJA.js} +13 -10
  50. package/dist/chunks/{importer-Bji2MeWr.js.map → importer-CKbUbsJA.js.map} +1 -1
  51. package/dist/chunks/{importer-CB_zV5_L.js → importer-ClCsdgTJ.js} +208 -1104
  52. package/dist/chunks/importer-ClCsdgTJ.js.map +1 -0
  53. package/dist/chunks/{importer-e3huMZbm.js → importer-CyVZTrf0.js} +14 -10
  54. package/dist/chunks/importer-CyVZTrf0.js.map +1 -0
  55. package/dist/chunks/{importer-CVT-JyDE.js → importer-DgG4v1Ms.js} +1537 -355
  56. package/dist/chunks/importer-DgG4v1Ms.js.map +1 -0
  57. package/dist/chunks/{importer-Cyy6UseH.js → importer-asFUrIsj.js} +66 -13
  58. package/dist/chunks/importer-asFUrIsj.js.map +1 -0
  59. package/dist/chunks/{input-Ccg9I22A.js → input-CAxt_aV-.js} +4 -4
  60. package/dist/chunks/{input-Ccg9I22A.js.map → input-CAxt_aV-.js.map} +1 -1
  61. package/dist/chunks/{json-elements-By172SVq.js → json-elements-Cq76WjnZ.js} +4 -4
  62. package/dist/chunks/{json-elements-By172SVq.js.map → json-elements-Cq76WjnZ.js.map} +1 -1
  63. package/dist/chunks/{lexicon-u2SI5xcx.js → lexicon-IVRq2Uoo.js} +282 -74
  64. package/dist/chunks/lexicon-IVRq2Uoo.js.map +1 -0
  65. package/dist/chunks/{ontology-export-BwgMyuF0.js → ontology-export-OMo91mb0.js} +4 -4
  66. package/dist/chunks/{ontology-export-BwgMyuF0.js.map → ontology-export-OMo91mb0.js.map} +1 -1
  67. package/dist/chunks/{records-Cgvxz-Vx.js → records-NJiYvekn.js} +2 -2
  68. package/dist/chunks/{records-Cgvxz-Vx.js.map → records-NJiYvekn.js.map} +1 -1
  69. package/dist/chunks/{report-CgdsL9Hb.js → report-CwMfYa9J.js} +23 -23
  70. package/dist/chunks/{report-CgdsL9Hb.js.map → report-CwMfYa9J.js.map} +1 -1
  71. package/dist/chunks/round-trip-Cy3_SHRZ.js +79 -0
  72. package/dist/chunks/round-trip-Cy3_SHRZ.js.map +1 -0
  73. package/dist/chunks/{sigv4-LkAzsLAu.js → sigv4-BXwVbza3.js} +5 -5
  74. package/dist/chunks/sigv4-BXwVbza3.js.map +1 -0
  75. package/dist/chunks/{styles-CaABMoO1.js → styles-CAVmBLgp.js} +1237 -138
  76. package/dist/chunks/styles-CAVmBLgp.js.map +1 -0
  77. package/dist/chunks/styles-CPczw1Jz.js +1928 -0
  78. package/dist/chunks/styles-CPczw1Jz.js.map +1 -0
  79. package/dist/chunks/styles-boK6Ln54.js +2847 -0
  80. package/dist/chunks/styles-boK6Ln54.js.map +1 -0
  81. package/dist/chunks/{styles-yed-Cs1nmrjn.js → styles-yed-XeFBQ6VS.js} +506 -175
  82. package/dist/chunks/styles-yed-XeFBQ6VS.js.map +1 -0
  83. package/dist/chunks/{text-BuKQVMz2.js → text-ystE2bYi.js} +2 -2
  84. package/dist/chunks/{text-BuKQVMz2.js.map → text-ystE2bYi.js.map} +1 -1
  85. package/dist/csv.js +7 -7
  86. package/dist/cx.js +2 -2
  87. package/dist/cx2.js +2 -2
  88. package/dist/cys.js +1 -1
  89. package/dist/dot.js +8 -4
  90. package/dist/dot.js.map +1 -1
  91. package/dist/gexf.js +42 -12
  92. package/dist/gexf.js.map +1 -1
  93. package/dist/gml.js +848 -194
  94. package/dist/gml.js.map +1 -1
  95. package/dist/graph-io.js +230 -193
  96. package/dist/graph-io.js.map +1 -1
  97. package/dist/graphml.js +3 -3
  98. package/dist/json.js +3 -2
  99. package/dist/neo4j.js +6 -6
  100. package/dist/obo.js +1 -1
  101. package/dist/pajek.js +1 -1
  102. package/dist/positions.js +45 -3
  103. package/dist/positions.js.map +1 -1
  104. package/dist/sources-cypher.js +141 -23
  105. package/dist/sources-cypher.js.map +1 -1
  106. package/dist/sources-ndex.js +2 -2
  107. package/dist/sources-rest.js +32 -6
  108. package/dist/sources-rest.js.map +1 -1
  109. package/dist/sources-sparql.d.ts +1 -0
  110. package/dist/sources-sparql.js +439 -0
  111. package/dist/sources-sparql.js.map +1 -0
  112. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  113. package/dist/src/formats/cx/importer.js +5 -1
  114. package/dist/src/formats/cx/importer.js.map +1 -1
  115. package/dist/src/formats/cx/styles.d.ts +24 -1
  116. package/dist/src/formats/cx/styles.d.ts.map +1 -1
  117. package/dist/src/formats/cx/styles.js +117 -11
  118. package/dist/src/formats/cx/styles.js.map +1 -1
  119. package/dist/src/formats/cx2/importer.d.ts.map +1 -1
  120. package/dist/src/formats/cx2/importer.js +1 -0
  121. package/dist/src/formats/cx2/importer.js.map +1 -1
  122. package/dist/src/formats/cx2/styles.d.ts.map +1 -1
  123. package/dist/src/formats/cx2/styles.js +3 -1
  124. package/dist/src/formats/cx2/styles.js.map +1 -1
  125. package/dist/src/formats/cys/importer.d.ts.map +1 -1
  126. package/dist/src/formats/cys/importer.js +1 -0
  127. package/dist/src/formats/cys/importer.js.map +1 -1
  128. package/dist/src/formats/cys/styles.d.ts +2 -0
  129. package/dist/src/formats/cys/styles.d.ts.map +1 -1
  130. package/dist/src/formats/cys/styles.js +15 -7
  131. package/dist/src/formats/cys/styles.js.map +1 -1
  132. package/dist/src/formats/dot/drawing.d.ts +98 -0
  133. package/dist/src/formats/dot/drawing.d.ts.map +1 -0
  134. package/dist/src/formats/dot/drawing.js +734 -0
  135. package/dist/src/formats/dot/drawing.js.map +1 -0
  136. package/dist/src/formats/dot/exporter.d.ts.map +1 -1
  137. package/dist/src/formats/dot/exporter.js +34 -2
  138. package/dist/src/formats/dot/exporter.js.map +1 -1
  139. package/dist/src/formats/dot/importer.d.ts +6 -1
  140. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  141. package/dist/src/formats/dot/importer.js +170 -33
  142. package/dist/src/formats/dot/importer.js.map +1 -1
  143. package/dist/src/formats/dot/index.d.ts +3 -1
  144. package/dist/src/formats/dot/index.d.ts.map +1 -1
  145. package/dist/src/formats/dot/index.js +2 -1
  146. package/dist/src/formats/dot/index.js.map +1 -1
  147. package/dist/src/formats/dot/label-places.d.ts +41 -0
  148. package/dist/src/formats/dot/label-places.d.ts.map +1 -0
  149. package/dist/src/formats/dot/label-places.js +185 -0
  150. package/dist/src/formats/dot/label-places.js.map +1 -0
  151. package/dist/src/formats/dot/names.d.ts +13 -0
  152. package/dist/src/formats/dot/names.d.ts.map +1 -1
  153. package/dist/src/formats/dot/names.js +13 -0
  154. package/dist/src/formats/dot/names.js.map +1 -1
  155. package/dist/src/formats/dot/record.d.ts +50 -0
  156. package/dist/src/formats/dot/record.d.ts.map +1 -0
  157. package/dist/src/formats/dot/record.js +275 -0
  158. package/dist/src/formats/dot/record.js.map +1 -0
  159. package/dist/src/formats/dot/styles.d.ts +72 -2
  160. package/dist/src/formats/dot/styles.d.ts.map +1 -1
  161. package/dist/src/formats/dot/styles.js +1500 -119
  162. package/dist/src/formats/dot/styles.js.map +1 -1
  163. package/dist/src/formats/gexf/dialog-metrics.d.ts +15 -0
  164. package/dist/src/formats/gexf/dialog-metrics.d.ts.map +1 -0
  165. package/dist/src/formats/gexf/dialog-metrics.js +59 -0
  166. package/dist/src/formats/gexf/dialog-metrics.js.map +1 -0
  167. package/dist/src/formats/gexf/importer.d.ts +7 -0
  168. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  169. package/dist/src/formats/gexf/importer.js +41 -5
  170. package/dist/src/formats/gexf/importer.js.map +1 -1
  171. package/dist/src/formats/gexf/preview.d.ts +77 -0
  172. package/dist/src/formats/gexf/preview.d.ts.map +1 -0
  173. package/dist/src/formats/gexf/preview.js +191 -0
  174. package/dist/src/formats/gexf/preview.js.map +1 -0
  175. package/dist/src/formats/gexf/schema.d.ts.map +1 -1
  176. package/dist/src/formats/gexf/schema.js +2 -1
  177. package/dist/src/formats/gexf/schema.js.map +1 -1
  178. package/dist/src/formats/gexf/styles.d.ts +58 -31
  179. package/dist/src/formats/gexf/styles.d.ts.map +1 -1
  180. package/dist/src/formats/gexf/styles.js +848 -225
  181. package/dist/src/formats/gexf/styles.js.map +1 -1
  182. package/dist/src/formats/gml/importer.d.ts +5 -2
  183. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  184. package/dist/src/formats/gml/importer.js +258 -71
  185. package/dist/src/formats/gml/importer.js.map +1 -1
  186. package/dist/src/formats/gml/index.d.ts +1 -1
  187. package/dist/src/formats/gml/index.d.ts.map +1 -1
  188. package/dist/src/formats/gml/index.js +1 -1
  189. package/dist/src/formats/gml/index.js.map +1 -1
  190. package/dist/src/formats/gml/positions.d.ts +7 -0
  191. package/dist/src/formats/gml/positions.d.ts.map +1 -1
  192. package/dist/src/formats/gml/positions.js +29 -7
  193. package/dist/src/formats/gml/positions.js.map +1 -1
  194. package/dist/src/formats/gml/styles.d.ts.map +1 -1
  195. package/dist/src/formats/gml/styles.js +754 -102
  196. package/dist/src/formats/gml/styles.js.map +1 -1
  197. package/dist/src/formats/graphml/styles-plain.d.ts.map +1 -1
  198. package/dist/src/formats/graphml/styles-plain.js +6 -10
  199. package/dist/src/formats/graphml/styles-plain.js.map +1 -1
  200. package/dist/src/formats/graphml/styles-yed.d.ts +21 -15
  201. package/dist/src/formats/graphml/styles-yed.d.ts.map +1 -1
  202. package/dist/src/formats/graphml/styles-yed.js +695 -164
  203. package/dist/src/formats/graphml/styles-yed.js.map +1 -1
  204. package/dist/src/formats/graphml/styles-yfiles3.d.ts +1 -1
  205. package/dist/src/formats/graphml/styles-yfiles3.d.ts.map +1 -1
  206. package/dist/src/formats/graphml/styles-yfiles3.js +431 -64
  207. package/dist/src/formats/graphml/styles-yfiles3.js.map +1 -1
  208. package/dist/src/formats/graphml/yfiles.d.ts +3 -3
  209. package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
  210. package/dist/src/formats/graphml/yfiles.js +16 -6
  211. package/dist/src/formats/graphml/yfiles.js.map +1 -1
  212. package/dist/src/formats/json/dialect.d.ts +3 -2
  213. package/dist/src/formats/json/dialect.d.ts.map +1 -1
  214. package/dist/src/formats/json/dialect.js +39 -5
  215. package/dist/src/formats/json/dialect.js.map +1 -1
  216. package/dist/src/formats/json/importer.d.ts +13 -2
  217. package/dist/src/formats/json/importer.d.ts.map +1 -1
  218. package/dist/src/formats/json/importer.js +42 -6
  219. package/dist/src/formats/json/importer.js.map +1 -1
  220. package/dist/src/formats/json/index.d.ts +1 -1
  221. package/dist/src/formats/json/index.d.ts.map +1 -1
  222. package/dist/src/formats/json/index.js +1 -1
  223. package/dist/src/formats/json/index.js.map +1 -1
  224. package/dist/src/formats/json/positions.d.ts +5 -2
  225. package/dist/src/formats/json/positions.d.ts.map +1 -1
  226. package/dist/src/formats/json/positions.js +20 -4
  227. package/dist/src/formats/json/positions.js.map +1 -1
  228. package/dist/src/formats/json/styles.d.ts +12 -1
  229. package/dist/src/formats/json/styles.d.ts.map +1 -1
  230. package/dist/src/formats/json/styles.js +1843 -136
  231. package/dist/src/formats/json/styles.js.map +1 -1
  232. package/dist/src/formats/pajek/draw.d.ts +104 -0
  233. package/dist/src/formats/pajek/draw.d.ts.map +1 -0
  234. package/dist/src/formats/pajek/draw.js +382 -0
  235. package/dist/src/formats/pajek/draw.js.map +1 -0
  236. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  237. package/dist/src/formats/pajek/exporter.js +70 -51
  238. package/dist/src/formats/pajek/exporter.js.map +1 -1
  239. package/dist/src/formats/pajek/importer.d.ts +9 -0
  240. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  241. package/dist/src/formats/pajek/importer.js +233 -102
  242. package/dist/src/formats/pajek/importer.js.map +1 -1
  243. package/dist/src/formats/pajek/index.d.ts +1 -0
  244. package/dist/src/formats/pajek/index.d.ts.map +1 -1
  245. package/dist/src/formats/pajek/index.js.map +1 -1
  246. package/dist/src/formats/pajek/styles.d.ts +15 -7
  247. package/dist/src/formats/pajek/styles.d.ts.map +1 -1
  248. package/dist/src/formats/pajek/styles.js +1395 -114
  249. package/dist/src/formats/pajek/styles.js.map +1 -1
  250. package/dist/src/formats/pajek/syntax.d.ts +10 -1
  251. package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
  252. package/dist/src/formats/pajek/syntax.js +26 -2
  253. package/dist/src/formats/pajek/syntax.js.map +1 -1
  254. package/dist/src/formats/xgmml/emit.d.ts +1 -0
  255. package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
  256. package/dist/src/formats/xgmml/emit.js +65 -5
  257. package/dist/src/formats/xgmml/emit.js.map +1 -1
  258. package/dist/src/formats/xgmml/styles.d.ts +23 -3
  259. package/dist/src/formats/xgmml/styles.d.ts.map +1 -1
  260. package/dist/src/formats/xgmml/styles.js +277 -60
  261. package/dist/src/formats/xgmml/styles.js.map +1 -1
  262. package/dist/src/index.d.ts +6 -5
  263. package/dist/src/index.d.ts.map +1 -1
  264. package/dist/src/index.js +6 -5
  265. package/dist/src/index.js.map +1 -1
  266. package/dist/src/positions/convert.d.ts.map +1 -1
  267. package/dist/src/positions/convert.js +11 -1
  268. package/dist/src/positions/convert.js.map +1 -1
  269. package/dist/src/positions/extract.d.ts.map +1 -1
  270. package/dist/src/positions/extract.js +53 -1
  271. package/dist/src/positions/extract.js.map +1 -1
  272. package/dist/src/positions/index.d.ts +1 -1
  273. package/dist/src/positions/index.d.ts.map +1 -1
  274. package/dist/src/positions/types.d.ts +59 -0
  275. package/dist/src/positions/types.d.ts.map +1 -1
  276. package/dist/src/sources/builtins.d.ts +1 -1
  277. package/dist/src/sources/builtins.d.ts.map +1 -1
  278. package/dist/src/sources/builtins.js +8 -2
  279. package/dist/src/sources/builtins.js.map +1 -1
  280. package/dist/src/sources/context.d.ts.map +1 -1
  281. package/dist/src/sources/context.js +1 -0
  282. package/dist/src/sources/context.js.map +1 -1
  283. package/dist/src/sources/credentials.d.ts +50 -1
  284. package/dist/src/sources/credentials.d.ts.map +1 -1
  285. package/dist/src/sources/credentials.js +69 -0
  286. package/dist/src/sources/credentials.js.map +1 -1
  287. package/dist/src/sources/cypher/descriptor.d.ts.map +1 -1
  288. package/dist/src/sources/cypher/descriptor.js +5 -0
  289. package/dist/src/sources/cypher/descriptor.js.map +1 -1
  290. package/dist/src/sources/cypher/index.d.ts.map +1 -1
  291. package/dist/src/sources/cypher/index.js +125 -18
  292. package/dist/src/sources/cypher/index.js.map +1 -1
  293. package/dist/src/sources/cypher/params.d.ts +1 -1
  294. package/dist/src/sources/cypher/params.d.ts.map +1 -1
  295. package/dist/src/sources/cypher/query-builder.d.ts +17 -0
  296. package/dist/src/sources/cypher/query-builder.d.ts.map +1 -1
  297. package/dist/src/sources/cypher/query-builder.js +31 -0
  298. package/dist/src/sources/cypher/query-builder.js.map +1 -1
  299. package/dist/src/sources/ids.d.ts +5 -0
  300. package/dist/src/sources/ids.d.ts.map +1 -1
  301. package/dist/src/sources/ids.js +5 -0
  302. package/dist/src/sources/ids.js.map +1 -1
  303. package/dist/src/sources/params.d.ts +3 -0
  304. package/dist/src/sources/params.d.ts.map +1 -1
  305. package/dist/src/sources/rest/descriptor.d.ts.map +1 -1
  306. package/dist/src/sources/rest/descriptor.js +9 -0
  307. package/dist/src/sources/rest/descriptor.js.map +1 -1
  308. package/dist/src/sources/rest/openalex.d.ts +4 -2
  309. package/dist/src/sources/rest/openalex.d.ts.map +1 -1
  310. package/dist/src/sources/rest/openalex.js +4 -2
  311. package/dist/src/sources/rest/openalex.js.map +1 -1
  312. package/dist/src/sources/rest/source.d.ts.map +1 -1
  313. package/dist/src/sources/rest/source.js +38 -0
  314. package/dist/src/sources/rest/source.js.map +1 -1
  315. package/dist/src/sources/run.d.ts +2 -0
  316. package/dist/src/sources/run.d.ts.map +1 -1
  317. package/dist/src/sources/run.js +30 -3
  318. package/dist/src/sources/run.js.map +1 -1
  319. package/dist/src/sources/sigv4.d.ts +5 -3
  320. package/dist/src/sources/sigv4.d.ts.map +1 -1
  321. package/dist/src/sources/sigv4.js +6 -4
  322. package/dist/src/sources/sigv4.js.map +1 -1
  323. package/dist/src/sources/sparql/descriptor.d.ts +10 -0
  324. package/dist/src/sources/sparql/descriptor.d.ts.map +1 -0
  325. package/dist/src/sources/sparql/descriptor.js +64 -0
  326. package/dist/src/sources/sparql/descriptor.js.map +1 -0
  327. package/dist/src/sources/sparql/index.d.ts +28 -0
  328. package/dist/src/sources/sparql/index.d.ts.map +1 -0
  329. package/dist/src/sources/sparql/index.js +327 -0
  330. package/dist/src/sources/sparql/index.js.map +1 -0
  331. package/dist/src/sources/sparql/ntriples.d.ts +69 -0
  332. package/dist/src/sources/sparql/ntriples.d.ts.map +1 -0
  333. package/dist/src/sources/sparql/ntriples.js +180 -0
  334. package/dist/src/sources/sparql/ntriples.js.map +1 -0
  335. package/dist/src/sources/sparql/params.d.ts +27 -0
  336. package/dist/src/sources/sparql/params.d.ts.map +1 -0
  337. package/dist/src/sources/sparql/params.js +5 -0
  338. package/dist/src/sources/sparql/params.js.map +1 -0
  339. package/dist/src/sources/sparql/query.d.ts +73 -0
  340. package/dist/src/sources/sparql/query.d.ts.map +1 -0
  341. package/dist/src/sources/sparql/query.js +164 -0
  342. package/dist/src/sources/sparql/query.js.map +1 -0
  343. package/dist/src/sources/types.d.ts +60 -0
  344. package/dist/src/sources/types.d.ts.map +1 -1
  345. package/dist/src/styles/annotations.d.ts +61 -5
  346. package/dist/src/styles/annotations.d.ts.map +1 -1
  347. package/dist/src/styles/annotations.js +130 -22
  348. package/dist/src/styles/annotations.js.map +1 -1
  349. package/dist/src/styles/canon/bends.d.ts +46 -0
  350. package/dist/src/styles/canon/bends.d.ts.map +1 -1
  351. package/dist/src/styles/canon/bends.js +123 -0
  352. package/dist/src/styles/canon/bends.js.map +1 -1
  353. package/dist/src/styles/canon/color-tables.d.ts +6 -1
  354. package/dist/src/styles/canon/color-tables.d.ts.map +1 -1
  355. package/dist/src/styles/canon/color-tables.js +10 -4
  356. package/dist/src/styles/canon/color-tables.js.map +1 -1
  357. package/dist/src/styles/canon/color.d.ts +3 -1
  358. package/dist/src/styles/canon/color.d.ts.map +1 -1
  359. package/dist/src/styles/canon/color.js +103 -3
  360. package/dist/src/styles/canon/color.js.map +1 -1
  361. package/dist/src/styles/canon/enums.d.ts +2 -2
  362. package/dist/src/styles/canon/enums.d.ts.map +1 -1
  363. package/dist/src/styles/canon/enums.js +89 -7
  364. package/dist/src/styles/canon/enums.js.map +1 -1
  365. package/dist/src/styles/canon/graphviz.d.ts +12 -3
  366. package/dist/src/styles/canon/graphviz.d.ts.map +1 -1
  367. package/dist/src/styles/canon/graphviz.js +57 -9
  368. package/dist/src/styles/canon/graphviz.js.map +1 -1
  369. package/dist/src/styles/canon/number.d.ts +8 -0
  370. package/dist/src/styles/canon/number.d.ts.map +1 -1
  371. package/dist/src/styles/canon/number.js +18 -0
  372. package/dist/src/styles/canon/number.js.map +1 -1
  373. package/dist/src/styles/canon/text.d.ts +29 -2
  374. package/dist/src/styles/canon/text.d.ts.map +1 -1
  375. package/dist/src/styles/canon/text.js +156 -16
  376. package/dist/src/styles/canon/text.js.map +1 -1
  377. package/dist/src/styles/codes.d.ts +2 -0
  378. package/dist/src/styles/codes.d.ts.map +1 -1
  379. package/dist/src/styles/codes.js +2 -0
  380. package/dist/src/styles/codes.js.map +1 -1
  381. package/dist/src/styles/cyjs/cascade.d.ts.map +1 -1
  382. package/dist/src/styles/cyjs/cascade.js +1139 -79
  383. package/dist/src/styles/cyjs/cascade.js.map +1 -1
  384. package/dist/src/styles/cyjs/defaults-table.d.ts.map +1 -1
  385. package/dist/src/styles/cyjs/defaults-table.js +4 -0
  386. package/dist/src/styles/cyjs/defaults-table.js.map +1 -1
  387. package/dist/src/styles/cyjs/emit.d.ts.map +1 -1
  388. package/dist/src/styles/cyjs/emit.js +232 -10
  389. package/dist/src/styles/cyjs/emit.js.map +1 -1
  390. package/dist/src/styles/cyjs/face.d.ts +20 -0
  391. package/dist/src/styles/cyjs/face.d.ts.map +1 -0
  392. package/dist/src/styles/cyjs/face.js +332 -0
  393. package/dist/src/styles/cyjs/face.js.map +1 -0
  394. package/dist/src/styles/cyjs/mappers.d.ts +44 -1
  395. package/dist/src/styles/cyjs/mappers.d.ts.map +1 -1
  396. package/dist/src/styles/cyjs/mappers.js +475 -26
  397. package/dist/src/styles/cyjs/mappers.js.map +1 -1
  398. package/dist/src/styles/cyjs/routes.d.ts +53 -0
  399. package/dist/src/styles/cyjs/routes.d.ts.map +1 -0
  400. package/dist/src/styles/cyjs/routes.js +360 -0
  401. package/dist/src/styles/cyjs/routes.js.map +1 -0
  402. package/dist/src/styles/cytoscape/charts.d.ts +23 -0
  403. package/dist/src/styles/cytoscape/charts.d.ts.map +1 -0
  404. package/dist/src/styles/cytoscape/charts.js +560 -0
  405. package/dist/src/styles/cytoscape/charts.js.map +1 -0
  406. package/dist/src/styles/cytoscape/emit.d.ts.map +1 -1
  407. package/dist/src/styles/cytoscape/emit.js +156 -48
  408. package/dist/src/styles/cytoscape/emit.js.map +1 -1
  409. package/dist/src/styles/cytoscape/lexicon.d.ts +91 -3
  410. package/dist/src/styles/cytoscape/lexicon.d.ts.map +1 -1
  411. package/dist/src/styles/cytoscape/lexicon.js +387 -77
  412. package/dist/src/styles/cytoscape/lexicon.js.map +1 -1
  413. package/dist/src/styles/cytoscape/mappings.d.ts +30 -0
  414. package/dist/src/styles/cytoscape/mappings.d.ts.map +1 -1
  415. package/dist/src/styles/cytoscape/mappings.js +92 -0
  416. package/dist/src/styles/cytoscape/mappings.js.map +1 -1
  417. package/dist/src/styles/cytoscape/resolve.d.ts +42 -2
  418. package/dist/src/styles/cytoscape/resolve.d.ts.map +1 -1
  419. package/dist/src/styles/cytoscape/resolve.js +623 -17
  420. package/dist/src/styles/cytoscape/resolve.js.map +1 -1
  421. package/dist/src/styles/defaults.d.ts +46 -26
  422. package/dist/src/styles/defaults.d.ts.map +1 -1
  423. package/dist/src/styles/defaults.js +308 -71
  424. package/dist/src/styles/defaults.js.map +1 -1
  425. package/dist/src/styles/index.d.ts +4 -3
  426. package/dist/src/styles/index.d.ts.map +1 -1
  427. package/dist/src/styles/index.js +3 -2
  428. package/dist/src/styles/index.js.map +1 -1
  429. package/dist/src/styles/internal.d.ts +1 -0
  430. package/dist/src/styles/internal.d.ts.map +1 -1
  431. package/dist/src/styles/internal.js +1 -0
  432. package/dist/src/styles/internal.js.map +1 -1
  433. package/dist/src/styles/io/generic.d.ts.map +1 -1
  434. package/dist/src/styles/io/generic.js +56 -16
  435. package/dist/src/styles/io/generic.js.map +1 -1
  436. package/dist/src/styles/io/round-trip.d.ts +56 -0
  437. package/dist/src/styles/io/round-trip.d.ts.map +1 -0
  438. package/dist/src/styles/io/round-trip.js +138 -0
  439. package/dist/src/styles/io/round-trip.js.map +1 -0
  440. package/dist/src/styles/io/writer.d.ts.map +1 -1
  441. package/dist/src/styles/io/writer.js +6 -1
  442. package/dist/src/styles/io/writer.js.map +1 -1
  443. package/dist/src/styles/notes.d.ts.map +1 -1
  444. package/dist/src/styles/notes.js +1 -0
  445. package/dist/src/styles/notes.js.map +1 -1
  446. package/dist/src/styles/plan/features.d.ts +1 -1
  447. package/dist/src/styles/plan/features.d.ts.map +1 -1
  448. package/dist/src/styles/plan/features.js +22 -2
  449. package/dist/src/styles/plan/features.js.map +1 -1
  450. package/dist/src/styles/plan/index.d.ts +1 -1
  451. package/dist/src/styles/plan/index.d.ts.map +1 -1
  452. package/dist/src/styles/plan/index.js +1 -1
  453. package/dist/src/styles/plan/index.js.map +1 -1
  454. package/dist/src/styles/plan/plan.d.ts.map +1 -1
  455. package/dist/src/styles/plan/plan.js +61 -4
  456. package/dist/src/styles/plan/plan.js.map +1 -1
  457. package/dist/src/styles/plan/resolve.d.ts +11 -0
  458. package/dist/src/styles/plan/resolve.d.ts.map +1 -1
  459. package/dist/src/styles/plan/resolve.js +40 -4
  460. package/dist/src/styles/plan/resolve.js.map +1 -1
  461. package/dist/src/styles/slots.d.ts +14 -0
  462. package/dist/src/styles/slots.d.ts.map +1 -0
  463. package/dist/src/styles/slots.js +20 -0
  464. package/dist/src/styles/slots.js.map +1 -0
  465. package/dist/src/styles/types.d.ts +687 -6
  466. package/dist/src/styles/types.d.ts.map +1 -1
  467. package/dist/src/styles/vocabulary.d.ts +3 -2
  468. package/dist/src/styles/vocabulary.d.ts.map +1 -1
  469. package/dist/src/styles/vocabulary.js +224 -0
  470. package/dist/src/styles/vocabulary.js.map +1 -1
  471. package/dist/styles.js +30 -239
  472. package/dist/styles.js.map +1 -1
  473. package/dist/xgmml.js +3 -3
  474. package/package.json +27 -7
  475. package/src/formats/cx/importer.ts +6 -1
  476. package/src/formats/cx/styles.ts +143 -9
  477. package/src/formats/cx2/importer.ts +1 -0
  478. package/src/formats/cx2/styles.ts +3 -1
  479. package/src/formats/cys/importer.ts +1 -0
  480. package/src/formats/cys/styles.ts +27 -5
  481. package/src/formats/dot/drawing.ts +799 -0
  482. package/src/formats/dot/exporter.ts +37 -1
  483. package/src/formats/dot/importer.ts +192 -36
  484. package/src/formats/dot/index.ts +3 -1
  485. package/src/formats/dot/label-places.ts +241 -0
  486. package/src/formats/dot/names.ts +15 -0
  487. package/src/formats/dot/record.ts +336 -0
  488. package/src/formats/dot/styles.ts +1702 -149
  489. package/src/formats/gexf/dialog-metrics.ts +61 -0
  490. package/src/formats/gexf/importer.ts +50 -5
  491. package/src/formats/gexf/preview.ts +217 -0
  492. package/src/formats/gexf/schema.ts +2 -1
  493. package/src/formats/gexf/styles.ts +1099 -245
  494. package/src/formats/gml/importer.ts +291 -76
  495. package/src/formats/gml/index.ts +1 -1
  496. package/src/formats/gml/positions.ts +29 -7
  497. package/src/formats/gml/styles.ts +852 -110
  498. package/src/formats/graphml/styles-plain.ts +6 -15
  499. package/src/formats/graphml/styles-yed.ts +765 -176
  500. package/src/formats/graphml/styles-yfiles3.ts +487 -63
  501. package/src/formats/graphml/yfiles.ts +19 -6
  502. package/src/formats/json/dialect.ts +41 -5
  503. package/src/formats/json/importer.ts +59 -7
  504. package/src/formats/json/index.ts +1 -0
  505. package/src/formats/json/positions.ts +22 -5
  506. package/src/formats/json/styles.ts +2123 -171
  507. package/src/formats/pajek/draw.ts +469 -0
  508. package/src/formats/pajek/exporter.ts +81 -49
  509. package/src/formats/pajek/importer.ts +278 -103
  510. package/src/formats/pajek/index.ts +1 -0
  511. package/src/formats/pajek/styles.ts +1506 -133
  512. package/src/formats/pajek/syntax.ts +27 -2
  513. package/src/formats/xgmml/emit.ts +73 -5
  514. package/src/formats/xgmml/styles.ts +330 -71
  515. package/src/index.ts +12 -1
  516. package/src/positions/convert.ts +12 -1
  517. package/src/positions/extract.ts +55 -1
  518. package/src/positions/index.ts +1 -0
  519. package/src/positions/types.ts +60 -0
  520. package/src/sources/builtins.ts +8 -1
  521. package/src/sources/context.ts +1 -0
  522. package/src/sources/credentials.ts +90 -1
  523. package/src/sources/cypher/descriptor.ts +7 -1
  524. package/src/sources/cypher/index.ts +149 -18
  525. package/src/sources/cypher/params.ts +1 -1
  526. package/src/sources/cypher/query-builder.ts +33 -0
  527. package/src/sources/ids.ts +6 -0
  528. package/src/sources/params.ts +3 -0
  529. package/src/sources/rest/descriptor.ts +9 -0
  530. package/src/sources/rest/openalex.ts +4 -2
  531. package/src/sources/rest/source.ts +41 -0
  532. package/src/sources/run.ts +35 -3
  533. package/src/sources/sigv4.ts +6 -4
  534. package/src/sources/sparql/descriptor.ts +67 -0
  535. package/src/sources/sparql/index.ts +371 -0
  536. package/src/sources/sparql/ntriples.ts +219 -0
  537. package/src/sources/sparql/params.ts +28 -0
  538. package/src/sources/sparql/query.ts +216 -0
  539. package/src/sources/types.ts +68 -0
  540. package/src/styles/annotations.ts +201 -27
  541. package/src/styles/canon/bends.ts +137 -0
  542. package/src/styles/canon/color-tables.ts +10 -4
  543. package/src/styles/canon/color.ts +105 -3
  544. package/src/styles/canon/enums.ts +107 -8
  545. package/src/styles/canon/graphviz.ts +71 -10
  546. package/src/styles/canon/number.ts +19 -0
  547. package/src/styles/canon/text.ts +187 -16
  548. package/src/styles/codes.ts +2 -0
  549. package/src/styles/cyjs/cascade.ts +1303 -84
  550. package/src/styles/cyjs/defaults-table.ts +4 -0
  551. package/src/styles/cyjs/emit.ts +268 -14
  552. package/src/styles/cyjs/face.ts +372 -0
  553. package/src/styles/cyjs/mappers.ts +506 -27
  554. package/src/styles/cyjs/routes.ts +432 -0
  555. package/src/styles/cytoscape/charts.ts +684 -0
  556. package/src/styles/cytoscape/emit.ts +170 -48
  557. package/src/styles/cytoscape/lexicon.ts +431 -78
  558. package/src/styles/cytoscape/mappings.ts +108 -0
  559. package/src/styles/cytoscape/resolve.ts +741 -17
  560. package/src/styles/defaults.ts +417 -108
  561. package/src/styles/index.ts +5 -0
  562. package/src/styles/internal.ts +1 -0
  563. package/src/styles/io/generic.ts +79 -23
  564. package/src/styles/io/round-trip.ts +202 -0
  565. package/src/styles/io/writer.ts +6 -1
  566. package/src/styles/notes.ts +1 -0
  567. package/src/styles/plan/features.ts +23 -2
  568. package/src/styles/plan/index.ts +1 -1
  569. package/src/styles/plan/plan.ts +69 -5
  570. package/src/styles/plan/resolve.ts +47 -4
  571. package/src/styles/slots.ts +25 -0
  572. package/src/styles/types.ts +698 -5
  573. package/src/styles/vocabulary.ts +232 -2
  574. package/dist/chunks/block-Cu22ewuS.js.map +0 -1
  575. package/dist/chunks/choose-Cdx6Enl2.js +0 -57
  576. package/dist/chunks/choose-Cdx6Enl2.js.map +0 -1
  577. package/dist/chunks/codes-CV_Bhcyi.js.map +0 -1
  578. package/dist/chunks/convert-BcQ8_jMo.js.map +0 -1
  579. package/dist/chunks/credentials-BiQsnMTb.js.map +0 -1
  580. package/dist/chunks/descriptor-BJ-W0Jd-.js.map +0 -1
  581. package/dist/chunks/emit-CD8xnY8s.js.map +0 -1
  582. package/dist/chunks/export-CZ7VRm4I.js.map +0 -1
  583. package/dist/chunks/exporter-bxxjOrDZ.js.map +0 -1
  584. package/dist/chunks/format-BMS-1Nxb.js +0 -64
  585. package/dist/chunks/format-BMS-1Nxb.js.map +0 -1
  586. package/dist/chunks/generic-CP6YD34u.js.map +0 -1
  587. package/dist/chunks/importer-B87_fmVx.js.map +0 -1
  588. package/dist/chunks/importer-CB_zV5_L.js.map +0 -1
  589. package/dist/chunks/importer-CVT-JyDE.js.map +0 -1
  590. package/dist/chunks/importer-Cyy6UseH.js.map +0 -1
  591. package/dist/chunks/importer-DPZDN40-.js.map +0 -1
  592. package/dist/chunks/importer-e3huMZbm.js.map +0 -1
  593. package/dist/chunks/lexicon-u2SI5xcx.js.map +0 -1
  594. package/dist/chunks/sigv4-LkAzsLAu.js.map +0 -1
  595. package/dist/chunks/styles-CaABMoO1.js.map +0 -1
  596. package/dist/chunks/styles-P_gmFAOi.js +0 -770
  597. package/dist/chunks/styles-P_gmFAOi.js.map +0 -1
  598. package/dist/chunks/styles-yed-Cs1nmrjn.js.map +0 -1
  599. package/dist/chunks/writer-DvHTl36J.js +0 -449
  600. package/dist/chunks/writer-DvHTl36J.js.map +0 -1
@@ -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,49 @@ 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 fails the load with `E_SOURCE_PARAM` (`name:
257
+ * "maxNodes"`, `reason: "uncappable"`): the query is never run past the cap the caller set.
258
+ * @param query - the query
259
+ * @param cursor - where to resume: `{ rows }` from an earlier capped run
260
+ * @returns the one page
261
+ */
262
+ private async userQuery(query: string, cursor: SourceCursor | null): Promise<Page> {
263
+ const { params, ctx } = this;
264
+ const parameters = params.parameters ?? {};
265
+ const asked = cursor?.rows ?? ctx.limits.maxNodes;
266
+ const rows =
267
+ asked === undefined || asked === null
268
+ ? null
269
+ : Number(checkedInteger(asked, "maxNodes", 1, Number.MAX_SAFE_INTEGER, ctx.report));
270
+ let result: QueryResult;
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 (rows === null || !(err instanceof ImportError) || err.issue?.code !== SOURCE_ISSUE.E_SOURCE_QUERY) {
280
+ throw err;
281
+ }
282
+ return failOn(ctx.report, "E_SOURCE_PARAM", "the server cannot cap this query; load it without maxNodes", {
283
+ name: "maxNodes",
284
+ reason: "uncappable",
285
+ });
286
+ }
287
+ const collected = new Collector();
288
+ collected.add(result, false);
289
+ requireGraph(result, collected, ctx.report);
290
+ const full = rows !== null && result.rows.length >= rows;
291
+ return { collected, next: full ? { rows: rows * 2 } : null };
234
292
  }
235
293
 
236
294
  /**
@@ -238,14 +296,33 @@ class Reader {
238
296
  * id expression (never SKIP), so a page is stable under unrelated writes.
239
297
  * @param profile - the server's profile
240
298
  * @param cursor - where to resume
299
+ * @param counting - whether a first page may count what the source holds
241
300
  * @yields one page at a time
242
301
  */
243
- private async *everything(profile: CypherProfile, cursor: SourceCursor | null): AsyncGenerator<Page> {
302
+ private async *everything(
303
+ profile: CypherProfile,
304
+ cursor: SourceCursor | null,
305
+ counting: boolean,
306
+ ): AsyncGenerator<Page> {
244
307
  const { params, ctx } = this;
245
308
  const size = checkedInteger(params.pageSize ?? DEFAULT_PAGE_SIZE, "pageSize", 1, MAX_PAGE_SIZE, ctx.report);
309
+ if (cursor === null && counting) {
310
+ this.counted = await this.count(profile);
311
+ }
312
+ const cap = ctx.limits.maxNodes;
313
+ if (cap !== undefined && cursor?.phase !== "edges") {
314
+ const capped = Number(checkedInteger(cap, "maxNodes", 1, Number.MAX_SAFE_INTEGER, ctx.report));
315
+ yield* this.cappedNodes(profile, cursor, Math.min(Number(size), capped));
316
+ return;
317
+ }
318
+
246
319
  let phase: "nodes" | "edges" = cursor?.phase === "edges" ? "edges" : "nodes";
247
320
  let after: string | number | boolean | null = cursor?.after ?? null;
248
- const total = params.countFirst === true && cursor === null ? await this.total() : undefined;
321
+ const { counted } = this;
322
+ const total =
323
+ params.countFirst === true && counted !== undefined
324
+ ? (counted.nodes ?? 0) + (counted.edges ?? 0)
325
+ : undefined;
249
326
  for (;;) {
250
327
  const nodes = phase === "nodes";
251
328
  const { collected, rows, fields } = await this.generated(
@@ -268,13 +345,66 @@ class Reader {
268
345
  }
269
346
 
270
347
  /**
271
- * How many nodes and relationships the filters match, for progress.
272
- * @returns the count
348
+ * Mode "all" under a node cap: pages of at most the cap's nodes, each with the relationships
349
+ * among the nodes loaded so far, so a capped load stops at its cap with its edges, and its
350
+ * next page (`data.more`) continues by key.
351
+ * @param profile - the server's profile
352
+ * @param cursor - where to resume
353
+ * @param size - the page size
354
+ * @yields one page at a time
355
+ */
356
+ private async *cappedNodes(
357
+ profile: CypherProfile,
358
+ cursor: SourceCursor | null,
359
+ size: number,
360
+ ): AsyncGenerator<Page> {
361
+ let after: string | number | boolean | null = cursor?.after ?? null;
362
+ for (;;) {
363
+ const { collected, rows, fields } = await this.generated(
364
+ (d) => nodePage(profile, this.filters, String(size), after !== null, d),
365
+ after === null ? {} : { after },
366
+ );
367
+ const at = fields.indexOf("key");
368
+ const last = rows.at(-1)?.[at];
369
+ const key = typeof last === "string" || typeof last === "number" ? last : null;
370
+ if (key !== null) {
371
+ const keys = rows.map((row) => row[at]);
372
+ const among = await this.transport.run(edgesAmong(profile, this.filters), { keys, last: key });
373
+ collected.add(among, false);
374
+ }
375
+ const next = rows.length >= size && key !== null ? { phase: "nodes", after: key } : null;
376
+ yield { collected, next };
377
+ if (next === null) {
378
+ return;
379
+ }
380
+ after = key;
381
+ }
382
+ }
383
+
384
+ /**
385
+ * What a first page of mode "all" counts: with `countFirst`, the nodes and relationships the
386
+ * filters match (for progress too); else, on Neo4j with at most one label and the server's
387
+ * ids, the nodes from the count store; else nothing.
388
+ * @param profile - the server's profile
389
+ * @returns the count, or undefined
273
390
  */
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);
391
+ private async count(profile: CypherProfile): Promise<SourceTotal | undefined> {
392
+ // A count is a non-negative integer; anything else a server answers is no count.
393
+ const first = async (statement: string): Promise<number | undefined> => {
394
+ const c = Number((await this.transport.run(statement, {})).rows[0]?.[0]);
395
+ return Number.isSafeInteger(c) && c >= 0 ? c : undefined;
396
+ };
397
+ const { labels, idProperty } = this.filters;
398
+ if (this.params.countFirst === true) {
399
+ const [n, r] = counts(this.filters);
400
+ const [nodes, edges] = await Promise.all([first(n), first(r)]);
401
+ return { ...(nodes === undefined ? {} : { nodes }), ...(edges === undefined ? {} : { edges }) };
402
+ }
403
+ if (profile.name !== "neo4j" || labels.length > 1 || idProperty !== null) {
404
+ return undefined;
405
+ }
406
+ const nodes = await first(storeCount(labels[0]));
407
+ return nodes === undefined ? undefined : { nodes };
278
408
  }
279
409
 
280
410
  /**
@@ -392,7 +522,8 @@ function cypher(preset: Preset): GraphSource<CypherParams> {
392
522
  break;
393
523
  }
394
524
  }
395
- return ctx.finish({ next, ...(await reader.facts(lines)) });
525
+ const total = reader.counted === undefined ? {} : { total: reader.counted };
526
+ return ctx.finish({ next, ...total, ...(await reader.facts(lines)) });
396
527
  }),
397
528
  expand: (request, sink, ctx) =>
398
529
  withReader(request.params, ctx, preset, (reader) => expand(reader, request, sink)),
@@ -404,7 +535,7 @@ function cypher(preset: Preset): GraphSource<CypherParams> {
404
535
  validate: (params, seen, ctx) =>
405
536
  withReader(params, ctx, preset, async (reader): Promise<SourceFreshness> => {
406
537
  const lines: string[] = [];
407
- for await (const page of reader.pages(null)) {
538
+ for await (const page of reader.pages(null, false)) {
408
539
  lines.push(...canonicalRows(page.collected, reader.idProperty));
409
540
  }
410
541
  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 that touch one node page: each
220
+ * starts from the page's own nodes `$keys` (an id or index lookup, never a scan of every
221
+ * relationship), with its other end on this page or an earlier one (at or before `$last`), so each
222
+ * relationship arrives once, with the page that loads its later end.
223
+ * @param profile - the server's profile
224
+ * @param filters - the filters
225
+ * @returns the statement; it reads `$keys` and `$last`
226
+ */
227
+ export function edgesAmong(profile: CypherProfile, filters: QueryFilters): string {
228
+ const ka = idExpression("a", profile, filters);
229
+ const kb = idExpression("b", profile, filters);
230
+ const ends = [nodePredicate("a", filters), nodePredicate("b", filters)].filter((p) => p !== null);
231
+ const rest = ends.length === 0 ? "" : ` AND ${ends.join(" AND ")}`;
232
+ const pattern = `MATCH (a)-[r${typesPattern(filters)}]->(b)`;
233
+ return [
234
+ `${pattern} WHERE ${ka} IN $keys AND ${kb} <= $last${rest} RETURN a, r, b`,
235
+ "UNION ALL",
236
+ `${pattern} WHERE ${kb} IN $keys AND ${ka} <= $last AND NOT ${ka} IN $keys${rest} RETURN a, r, b`,
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
@@ -6,6 +6,7 @@
6
6
  import { type CypherParams } from "./cypher/params.js";
7
7
  import { type NdexParams } from "./ndex/params.js";
8
8
  import { type OpenAlexParams, type RestParams } from "./rest/params.js";
9
+ import { type SparqlParams } from "./sparql/params.js";
9
10
 
10
11
  /**
11
12
  * Parameter types by source id; extend it by declaration merging:
@@ -26,4 +27,6 @@ export interface SourceParamsMap {
26
27
  rest: RestParams;
27
28
  /** OpenAlex. */
28
29
  openalex: OpenAlexParams;
30
+ /** Any SPARQL 1.1 endpoint. */
31
+ sparql: SparqlParams;
29
32
  }
@@ -17,6 +17,8 @@ export const REST_DESCRIPTOR: SourceDescriptor = Object.freeze({
17
17
  version: 1,
18
18
  auth: ["bearer", "api-key"],
19
19
  authRequired: "optional",
20
+ // ponytail: a mapping without `expand` or paging cannot do either; per-mapping features when a form needs them
21
+ features: ["expand", "probe", "validate", "page"],
20
22
  params: [{ name: "mapping", plainName: "Mapping", type: "text", required: true }],
21
23
  samples: [
22
24
  {
@@ -47,7 +49,13 @@ export const OPENALEX_DESCRIPTOR: SourceDescriptor = Object.freeze({
47
49
  defaultEndpoint: "https://api.openalex.org",
48
50
  auth: ["api-key"],
49
51
  authRequired: "optional",
52
+ // OpenAlex documents its key as the api_key query parameter
53
+ credentials: [
54
+ { name: "api_key", kind: "api-key", required: false, plainName: "API key", send: { query: "api_key" } },
55
+ ],
56
+ apiKey: { query: "api_key" },
50
57
  rateLimit: { requests: 10, perMs: 1000 },
58
+ features: ["expand", "probe", "validate", "page"],
51
59
  params: [
52
60
  { name: "work", plainName: "Work", type: "string" },
53
61
  { name: "author", plainName: "Author", type: "string" },
@@ -69,6 +77,7 @@ export const OPENALEX_DESCRIPTOR: SourceDescriptor = Object.freeze({
69
77
  plainName: "Watts-Strogatz paper's citations",
70
78
  params: { work: "W2112090702" },
71
79
  whole: false,
80
+ firstPage: 200,
72
81
  },
73
82
  ],
74
83
  });
@@ -266,8 +266,10 @@ const methods = restMethods<OpenAlexParams>(plan, false);
266
266
  * The OpenAlex preset (https://openalex.org): `work` (the citation graph around a work, default)
267
267
  * or `author` (the works they wrote), `graph: "coauthorship"` for authors joined by shared works,
268
268
  * and `include` (`"authors"`, `"institutions"`, `"topics"`) for more node kinds. Without a key,
269
- * the first page loads and a later one warns W_SOURCE_AUTH with `report.source.next`; pass
270
- * `credentials.apiKey({ query: "api_key" }, key)` and continue with the cursor. Experimental.
269
+ * the first page loads and a later one warns W_SOURCE_AUTH with `report.source.next`. Its one
270
+ * optional credential slot, `api_key`, is sent as the `api_key` query parameter: pass
271
+ * `credentials.forSlot(slot, key)` (or `credentials.apiKey({ query: "api_key" }, key)`) and
272
+ * continue with the cursor. Experimental.
271
273
  * @category Network sources
272
274
  */
273
275
  export const openalexSource: GraphSource<OpenAlexParams> = defineSource<OpenAlexParams>({
@@ -19,6 +19,7 @@ import {
19
19
  type GraphSource,
20
20
  type RecordBatch,
21
21
  type SourceContext,
22
+ type SourceCredentialSlot,
22
23
  type SourceCursor,
23
24
  type SourceDescriptor,
24
25
  type SourceFinish,
@@ -697,6 +698,44 @@ export type RestSourceInfo = {
697
698
  readonly id: string;
698
699
  } & Partial<SourceDescriptor>;
699
700
 
701
+ /**
702
+ * The credential slot a mapping's `auth` describes: an API key's slot is named by the query
703
+ * parameter or header it is sent in (`{ query: "api_key" }` is the slot `api_key`), a bearer
704
+ * token's is `default`. Optional, as a mapping cannot say a key is required.
705
+ * @param mapping - the mapping
706
+ * @returns the slots
707
+ */
708
+ function mappingSlots(mapping: RestMapping): readonly SourceCredentialSlot[] {
709
+ const { auth } = mapping;
710
+ if (auth === undefined) {
711
+ return [];
712
+ }
713
+ if (auth.kind === "bearer") {
714
+ return [{ name: "default", kind: "bearer", required: false }];
715
+ }
716
+ const { header } = auth;
717
+ if (header !== undefined) {
718
+ return [{ name: header.toLowerCase(), kind: "api-key", required: false, send: { header } }];
719
+ }
720
+ const query = auth.query ?? "api_key";
721
+ return [{ name: query, kind: "api-key", required: false, send: { query } }];
722
+ }
723
+
724
+ /**
725
+ * Where a mapping's API key goes, as a descriptor says it.
726
+ * @param auth - the mapping's auth
727
+ * @returns `{ apiKey }`, or nothing when the mapping takes no key or does not say where
728
+ */
729
+ function apiKeyOf(auth: RestMapping["auth"]): Pick<SourceDescriptor, "apiKey"> {
730
+ if (auth?.kind !== "api-key") {
731
+ return {};
732
+ }
733
+ if (auth.header !== undefined) {
734
+ return { apiKey: { header: auth.header } };
735
+ }
736
+ return auth.query === undefined ? {} : { apiKey: { query: auth.query } };
737
+ }
738
+
700
739
  /**
701
740
  * Turn a REST mapping into a source: a `records` source that loads the mapping's `load` request
702
741
  * page by page, with `expand` (breadth-first over the `expand` requests, `{ids}` batched; depth 0
@@ -733,6 +772,8 @@ export function restSource(mapping: RestMapping, info: RestSourceInfo): GraphSou
733
772
  defaultEndpoint: mapping.endpoint,
734
773
  auth,
735
774
  authRequired: auth.length === 0 ? "none" : "optional",
775
+ credentials: mappingSlots(mapping),
776
+ ...apiKeyOf(mapping.auth),
736
777
  ...(mapping.rateLimit === undefined ? {} : { rateLimit: mapping.rateLimit }),
737
778
  ...fields,
738
779
  });
@@ -15,7 +15,7 @@ import { type FormatRegistry } from "../registry.js";
15
15
  import { SNIFF_HEAD_BYTES } from "../sniff.js";
16
16
  import { type CommonImportOptions, ImportError, type ImportInput, type ImportReport } from "../types.js";
17
17
  import { type CreatedContext, createSourceContext, detectRuntime, LimitStop } from "./context.js";
18
- import { originOf } from "./credentials.js";
18
+ import { credentialQuery, originOf } from "./credentials.js";
19
19
  import { checkParams } from "./define.js";
20
20
  import { failOn, warnOn } from "./fail.js";
21
21
  import { SOURCE_FORMAT_PREFIX } from "./ids.js";
@@ -60,6 +60,8 @@ interface Prepared {
60
60
  readonly params: Record<string, unknown>;
61
61
  /** The sink wrapper's counters, set once the sink is known. */
62
62
  readonly counts: { nodes: Set<number>; edgesAtStart: number; sink: GraphSink | null };
63
+ /** The query parameter the call's credential is sent in, which a cursor never keeps; null for none. */
64
+ readonly secretQuery: string | null;
63
65
  }
64
66
 
65
67
  /**
@@ -131,7 +133,8 @@ function prepare(
131
133
  edges: counts.sink === null ? 0 : counts.sink.edgeCount - counts.edgesAtStart,
132
134
  }),
133
135
  });
134
- return { report, created, params, counts };
136
+ const secretQuery = options.credential === undefined ? null : credentialQuery(options.credential);
137
+ return { report, created, params, counts, secretQuery };
135
138
  }
136
139
 
137
140
  /**
@@ -721,6 +724,7 @@ export async function runMethod<T>(
721
724
  */
722
725
  export function withSource(report: ImportReport, prepared: Prepared, next: SourceCursor | null): ImportReport {
723
726
  const own = prepared.report.finish();
727
+ const cursor = prepared.secretQuery === null || next === null ? next : withoutParam(next, prepared.secretQuery);
724
728
  // issues the context recorded (retries, limits) that a source's own report does not hold
725
729
  const missing = own.issues.filter((i) => !report.issues.includes(i));
726
730
  return Object.freeze({
@@ -728,10 +732,38 @@ export function withSource(report: ImportReport, prepared: Prepared, next: Sourc
728
732
  issues: missing.length === 0 ? report.issues : Object.freeze([...report.issues, ...missing]),
729
733
  warningCount: report.warningCount + missing.filter((i) => i.severity === "warning").length,
730
734
  errorCount: report.errorCount + missing.filter((i) => i.severity === "error").length,
731
- source: prepared.created.info(next),
735
+ source: prepared.created.info(cursor),
732
736
  });
733
737
  }
734
738
 
739
+ /**
740
+ * A cursor without a query parameter in any URL it holds: a next-page link a service returns
741
+ * repeats the API key the request carried, and a cursor is saved where a credential never is.
742
+ * The credential is sent again with every request, so the next page does not need it there.
743
+ * @param value - the cursor, or a value inside it
744
+ * @param name - the parameter
745
+ * @returns the value without it
746
+ */
747
+ function withoutParam<T>(value: T, name: string): T {
748
+ if (typeof value === "string" && /^https?:\/\//i.test(value)) {
749
+ const url = new URL(value);
750
+ if (!url.searchParams.has(name)) {
751
+ return value;
752
+ }
753
+ url.searchParams.delete(name);
754
+ return url.href as T;
755
+ }
756
+ if (Array.isArray(value)) {
757
+ return Object.freeze(value.map((each: unknown) => withoutParam(each, name))) as T;
758
+ }
759
+ if (typeof value === "object" && value !== null) {
760
+ return Object.freeze(
761
+ Object.fromEntries(Object.entries(value).map(([key, each]) => [key, withoutParam(each, name)])),
762
+ ) as T;
763
+ }
764
+ return value;
765
+ }
766
+
735
767
  /**
736
768
  * What a failed call throws: the signal's reason when it aborted, an ImportError with the source
737
769
  * info attached, or the error itself.
@@ -75,12 +75,14 @@ async function sha256(data: Uint8Array | ArrayBuffer): Promise<string> {
75
75
  }
76
76
 
77
77
  /**
78
- * SHA-256 of a text's UTF-8 bytes, as lowercase hex (the Cypher source's content hash).
79
- * @param text - the text
78
+ * SHA-256 as 64 lowercase hexadecimal digits: of bytes exactly as given, or of a text's UTF-8 bytes
79
+ * (the Cypher source's content hash, a project file's record of a file it loaded). Web Crypto where
80
+ * there is one, else plain JavaScript (a page that is not a secure context). Experimental.
81
+ * @param data - the bytes or the text
80
82
  * @returns the digest
81
83
  */
82
- export function sha256Hex(text: string): Promise<string> {
83
- return sha256(utf8(text));
84
+ export function sha256Hex(data: string | Uint8Array): Promise<string> {
85
+ return sha256(typeof data === "string" ? utf8(data) : data);
84
86
  }
85
87
 
86
88
  /**
@@ -0,0 +1,67 @@
1
+ /**
2
+ * The SPARQL source's descriptor: catalog data, available without loading the source's code.
3
+ */
4
+
5
+ import { type SourceDescriptor } from "../types.js";
6
+
7
+ /** A small Wikidata query: physics Nobel laureates and their doctoral advisors. */
8
+ const WIKIDATA_ADVISORS = `PREFIX wd: <http://www.wikidata.org/entity/>
9
+ PREFIX wdt: <http://www.wikidata.org/prop/direct/>
10
+ PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
11
+ CONSTRUCT { ?person wdt:P184 ?advisor . ?person rdfs:label ?name . ?advisor rdfs:label ?advisorName . }
12
+ WHERE {
13
+ ?person wdt:P166 wd:Q38104 ; wdt:P184 ?advisor ; rdfs:label ?name .
14
+ ?advisor rdfs:label ?advisorName .
15
+ FILTER(lang(?name) = "en" && lang(?advisorName) = "en")
16
+ }`;
17
+
18
+ /**
19
+ * The descriptor of the `sparql` source. Experimental.
20
+ * @category Network sources
21
+ */
22
+ export const SPARQL_DESCRIPTOR: SourceDescriptor = Object.freeze({
23
+ plainName: "SPARQL endpoint",
24
+ kind: "sparql",
25
+ version: 1,
26
+ auth: ["basic", "bearer"],
27
+ authRequired: "optional",
28
+ features: ["expand", "probe", "validate", "page"],
29
+ params: [
30
+ { name: "query", plainName: "Query", type: "query", language: "sparql" },
31
+ {
32
+ name: "mode",
33
+ plainName: "Mode",
34
+ type: "enum",
35
+ values: [
36
+ { value: "query", label: "Query" },
37
+ { value: "all", label: "Everything" },
38
+ { value: "neighborhood", label: "Seed nodes" },
39
+ ],
40
+ },
41
+ { name: "ids", plainName: "Seed IRIs", type: "node-id" },
42
+ { name: "language", plainName: "Language", type: "string", advanced: true },
43
+ { name: "predicates", plainName: "Follow predicates", type: "string", advanced: true },
44
+ {
45
+ name: "pageSize",
46
+ plainName: "Page size",
47
+ type: "integer",
48
+ default: 1000,
49
+ min: 1,
50
+ max: 10000,
51
+ advanced: true,
52
+ },
53
+ ],
54
+ samples: [
55
+ {
56
+ id: "wikidata-physics-advisors",
57
+ plainName: "Wikidata: physics Nobel laureates and their advisors",
58
+ endpoint: "https://query.wikidata.org/sparql",
59
+ params: {
60
+ query: WIKIDATA_ADVISORS,
61
+ pageSize: 100,
62
+ language: "en",
63
+ predicates: ["http://www.wikidata.org/prop/direct/"], // NOSONAR(S5332): an RDF namespace IRI, never fetched; Wikidata's IRIs are http
64
+ },
65
+ },
66
+ ],
67
+ });