@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.
- package/dist/chunks/{approximations-C2riR4NT.js → approximations-Bzn3L-je.js} +2 -2
- package/dist/chunks/{approximations-C2riR4NT.js.map → approximations-Bzn3L-je.js.map} +1 -1
- package/dist/chunks/bends-BGXjv_U4.js +129 -0
- package/dist/chunks/bends-BGXjv_U4.js.map +1 -0
- package/dist/chunks/{block-Cu22ewuS.js → block-iptrlMBb.js} +906 -164
- package/dist/chunks/block-iptrlMBb.js.map +1 -0
- package/dist/chunks/choose-CczZJaX_.js +717 -0
- package/dist/chunks/choose-CczZJaX_.js.map +1 -0
- package/dist/chunks/{codes-CV_Bhcyi.js → codes-BE2xir2k.js} +6 -2
- package/dist/chunks/codes-BE2xir2k.js.map +1 -0
- package/dist/chunks/{constants-D0LqcsLJ.js → constants-CKkYLPtt.js} +2 -2
- package/dist/chunks/{constants-D0LqcsLJ.js.map → constants-CKkYLPtt.js.map} +1 -1
- package/dist/chunks/{context-cgmmOxZ2.js → context-C3p0RQxR.js} +5 -4
- package/dist/chunks/{context-cgmmOxZ2.js.map → context-C3p0RQxR.js.map} +1 -1
- package/dist/chunks/{convert-BcQ8_jMo.js → convert-Ct2zelbQ.js} +7 -2
- package/dist/chunks/convert-Ct2zelbQ.js.map +1 -0
- package/dist/chunks/{credentials-BiQsnMTb.js → credentials-DXHx7nwR.js} +16 -14
- package/dist/chunks/credentials-DXHx7nwR.js.map +1 -0
- package/dist/chunks/{cx-export-BEeF6ymo.js → cx-export-Bt6NoqTQ.js} +3 -3
- package/dist/chunks/{cx-export-BEeF6ymo.js.map → cx-export-Bt6NoqTQ.js.map} +1 -1
- package/dist/chunks/descriptor-B28U25x4.js +60 -0
- package/dist/chunks/descriptor-B28U25x4.js.map +1 -0
- package/dist/chunks/{descriptor-BJ-W0Jd-.js → descriptor-DLA5kINx.js} +7 -2
- package/dist/chunks/descriptor-DLA5kINx.js.map +1 -0
- package/dist/chunks/{emit-CD8xnY8s.js → emit-BwHQkZle.js} +1660 -133
- package/dist/chunks/emit-BwHQkZle.js.map +1 -0
- package/dist/chunks/{escape-DH2Egt-l.js → escape-CuCIzNMB.js} +8 -8
- package/dist/chunks/{escape-DH2Egt-l.js.map → escape-CuCIzNMB.js.map} +1 -1
- package/dist/chunks/{export-CZ7VRm4I.js → export-Cha4dRFz.js} +45 -387
- package/dist/chunks/export-Cha4dRFz.js.map +1 -0
- package/dist/chunks/{exporter-Dcw7Ldtq.js → exporter-BP6otMO6.js} +6 -6
- package/dist/chunks/{exporter-Dcw7Ldtq.js.map → exporter-BP6otMO6.js.map} +1 -1
- package/dist/chunks/{exporter-bxxjOrDZ.js → exporter-D2CETOMK.js} +1222 -156
- package/dist/chunks/exporter-D2CETOMK.js.map +1 -0
- package/dist/chunks/{exporter-BIdaoIgh.js → exporter-D9yMtocA.js} +7 -7
- package/dist/chunks/{exporter-BIdaoIgh.js.map → exporter-D9yMtocA.js.map} +1 -1
- package/dist/chunks/{exporter-DtVU80Fa.js → exporter-_jrBTnos.js} +9 -8
- package/dist/chunks/{exporter-DtVU80Fa.js.map → exporter-_jrBTnos.js.map} +1 -1
- package/dist/chunks/{exporter-ChjL5fmP.js → exporter-nDfxIK5D.js} +9 -8
- package/dist/chunks/{exporter-ChjL5fmP.js.map → exporter-nDfxIK5D.js.map} +1 -1
- package/dist/chunks/format-BXiAb-1h.js +408 -0
- package/dist/chunks/format-BXiAb-1h.js.map +1 -0
- package/dist/chunks/{generic-CP6YD34u.js → generic-ymWCETAJ.js} +387 -31
- package/dist/chunks/generic-ymWCETAJ.js.map +1 -0
- package/dist/chunks/{importer-e3huMZbm.js → importer-B92x1xY5.js} +14 -10
- package/dist/chunks/importer-B92x1xY5.js.map +1 -0
- package/dist/chunks/{importer-B87_fmVx.js → importer-CT9mJ1nn.js} +326 -84
- package/dist/chunks/importer-CT9mJ1nn.js.map +1 -0
- package/dist/chunks/{importer-CB_zV5_L.js → importer-DaLTjbds.js} +116 -1102
- package/dist/chunks/importer-DaLTjbds.js.map +1 -0
- package/dist/chunks/{importer-DPZDN40-.js → importer-GREKMdIf.js} +25 -17
- package/dist/chunks/importer-GREKMdIf.js.map +1 -0
- package/dist/chunks/{importer-Bji2MeWr.js → importer-PqaaKKnY.js} +13 -10
- package/dist/chunks/{importer-Bji2MeWr.js.map → importer-PqaaKKnY.js.map} +1 -1
- package/dist/chunks/{importer-Cyy6UseH.js → importer-Vn5QvmmJ.js} +66 -13
- package/dist/chunks/importer-Vn5QvmmJ.js.map +1 -0
- package/dist/chunks/{importer-CVT-JyDE.js → importer-vRq4h3j5.js} +1469 -356
- package/dist/chunks/importer-vRq4h3j5.js.map +1 -0
- package/dist/chunks/{input-Ccg9I22A.js → input-CAxt_aV-.js} +4 -4
- package/dist/chunks/{input-Ccg9I22A.js.map → input-CAxt_aV-.js.map} +1 -1
- package/dist/chunks/{json-elements-By172SVq.js → json-elements-Cq76WjnZ.js} +4 -4
- package/dist/chunks/{json-elements-By172SVq.js.map → json-elements-Cq76WjnZ.js.map} +1 -1
- package/dist/chunks/{lexicon-u2SI5xcx.js → lexicon-Clf4QIyl.js} +282 -74
- package/dist/chunks/lexicon-Clf4QIyl.js.map +1 -0
- package/dist/chunks/{ontology-export-BwgMyuF0.js → ontology-export-OMo91mb0.js} +4 -4
- package/dist/chunks/{ontology-export-BwgMyuF0.js.map → ontology-export-OMo91mb0.js.map} +1 -1
- package/dist/chunks/{records-Cgvxz-Vx.js → records-NJiYvekn.js} +2 -2
- package/dist/chunks/{records-Cgvxz-Vx.js.map → records-NJiYvekn.js.map} +1 -1
- package/dist/chunks/{report-CgdsL9Hb.js → report-CwMfYa9J.js} +23 -23
- package/dist/chunks/{report-CgdsL9Hb.js.map → report-CwMfYa9J.js.map} +1 -1
- package/dist/chunks/round-trip-Zm3_ivgq.js +79 -0
- package/dist/chunks/round-trip-Zm3_ivgq.js.map +1 -0
- package/dist/chunks/{sigv4-LkAzsLAu.js → sigv4-EokFic1V.js} +5 -5
- package/dist/chunks/sigv4-EokFic1V.js.map +1 -0
- package/dist/chunks/{styles-CaABMoO1.js → styles-CCs214_3.js} +1237 -138
- package/dist/chunks/styles-CCs214_3.js.map +1 -0
- package/dist/chunks/styles-Cm62yyQX.js +2812 -0
- package/dist/chunks/styles-Cm62yyQX.js.map +1 -0
- package/dist/chunks/styles-DPQQIig4.js +1928 -0
- package/dist/chunks/styles-DPQQIig4.js.map +1 -0
- package/dist/chunks/{styles-yed-Cs1nmrjn.js → styles-yed-UMFdNqze.js} +503 -172
- package/dist/chunks/styles-yed-UMFdNqze.js.map +1 -0
- package/dist/chunks/{text-BuKQVMz2.js → text-ystE2bYi.js} +2 -2
- package/dist/chunks/{text-BuKQVMz2.js.map → text-ystE2bYi.js.map} +1 -1
- package/dist/csv.js +7 -7
- package/dist/cx.js +2 -2
- package/dist/cx2.js +2 -2
- package/dist/cys.js +1 -1
- package/dist/dot.js +5 -4
- package/dist/dot.js.map +1 -1
- package/dist/gexf.js +42 -12
- package/dist/gexf.js.map +1 -1
- package/dist/gml.js +847 -193
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +232 -220
- package/dist/graph-io.js.map +1 -1
- package/dist/graphml.js +3 -3
- package/dist/json.js +3 -2
- package/dist/neo4j.js +6 -6
- package/dist/obo.js +1 -1
- package/dist/pajek.js +1 -1
- package/dist/positions.js +45 -3
- package/dist/positions.js.map +1 -1
- package/dist/sources-cypher.js +138 -23
- package/dist/sources-cypher.js.map +1 -1
- package/dist/sources-ndex.js +2 -2
- package/dist/sources-rest.js +16 -6
- package/dist/sources-rest.js.map +1 -1
- package/dist/sources-sparql.d.ts +1 -0
- package/dist/sources-sparql.js +405 -0
- package/dist/sources-sparql.js.map +1 -0
- package/dist/src/formats/cx/importer.d.ts.map +1 -1
- package/dist/src/formats/cx/importer.js +5 -1
- package/dist/src/formats/cx/importer.js.map +1 -1
- package/dist/src/formats/cx/styles.d.ts +24 -1
- package/dist/src/formats/cx/styles.d.ts.map +1 -1
- package/dist/src/formats/cx/styles.js +117 -11
- package/dist/src/formats/cx/styles.js.map +1 -1
- package/dist/src/formats/cx2/importer.d.ts.map +1 -1
- package/dist/src/formats/cx2/importer.js +1 -0
- package/dist/src/formats/cx2/importer.js.map +1 -1
- package/dist/src/formats/cx2/styles.d.ts.map +1 -1
- package/dist/src/formats/cx2/styles.js +3 -1
- package/dist/src/formats/cx2/styles.js.map +1 -1
- package/dist/src/formats/cys/importer.d.ts.map +1 -1
- package/dist/src/formats/cys/importer.js +1 -0
- package/dist/src/formats/cys/importer.js.map +1 -1
- package/dist/src/formats/cys/styles.d.ts +2 -0
- package/dist/src/formats/cys/styles.d.ts.map +1 -1
- package/dist/src/formats/cys/styles.js +15 -7
- package/dist/src/formats/cys/styles.js.map +1 -1
- package/dist/src/formats/dot/drawing.d.ts +98 -0
- package/dist/src/formats/dot/drawing.d.ts.map +1 -0
- package/dist/src/formats/dot/drawing.js +734 -0
- package/dist/src/formats/dot/drawing.js.map +1 -0
- package/dist/src/formats/dot/importer.d.ts.map +1 -1
- package/dist/src/formats/dot/importer.js +108 -31
- package/dist/src/formats/dot/importer.js.map +1 -1
- package/dist/src/formats/dot/label-places.d.ts +34 -0
- package/dist/src/formats/dot/label-places.d.ts.map +1 -0
- package/dist/src/formats/dot/label-places.js +179 -0
- package/dist/src/formats/dot/label-places.js.map +1 -0
- package/dist/src/formats/dot/record.d.ts +50 -0
- package/dist/src/formats/dot/record.d.ts.map +1 -0
- package/dist/src/formats/dot/record.js +275 -0
- package/dist/src/formats/dot/record.js.map +1 -0
- package/dist/src/formats/dot/styles.d.ts +62 -2
- package/dist/src/formats/dot/styles.d.ts.map +1 -1
- package/dist/src/formats/dot/styles.js +1454 -119
- package/dist/src/formats/dot/styles.js.map +1 -1
- package/dist/src/formats/gexf/dialog-metrics.d.ts +15 -0
- package/dist/src/formats/gexf/dialog-metrics.d.ts.map +1 -0
- package/dist/src/formats/gexf/dialog-metrics.js +59 -0
- package/dist/src/formats/gexf/dialog-metrics.js.map +1 -0
- package/dist/src/formats/gexf/importer.d.ts +7 -0
- package/dist/src/formats/gexf/importer.d.ts.map +1 -1
- package/dist/src/formats/gexf/importer.js +41 -5
- package/dist/src/formats/gexf/importer.js.map +1 -1
- package/dist/src/formats/gexf/preview.d.ts +77 -0
- package/dist/src/formats/gexf/preview.d.ts.map +1 -0
- package/dist/src/formats/gexf/preview.js +191 -0
- package/dist/src/formats/gexf/preview.js.map +1 -0
- package/dist/src/formats/gexf/schema.d.ts.map +1 -1
- package/dist/src/formats/gexf/schema.js +2 -1
- package/dist/src/formats/gexf/schema.js.map +1 -1
- package/dist/src/formats/gexf/styles.d.ts +58 -31
- package/dist/src/formats/gexf/styles.d.ts.map +1 -1
- package/dist/src/formats/gexf/styles.js +848 -225
- package/dist/src/formats/gexf/styles.js.map +1 -1
- package/dist/src/formats/gml/importer.d.ts +5 -2
- package/dist/src/formats/gml/importer.d.ts.map +1 -1
- package/dist/src/formats/gml/importer.js +258 -71
- package/dist/src/formats/gml/importer.js.map +1 -1
- package/dist/src/formats/gml/index.d.ts +1 -1
- package/dist/src/formats/gml/index.d.ts.map +1 -1
- package/dist/src/formats/gml/index.js +1 -1
- package/dist/src/formats/gml/index.js.map +1 -1
- package/dist/src/formats/gml/positions.d.ts +7 -0
- package/dist/src/formats/gml/positions.d.ts.map +1 -1
- package/dist/src/formats/gml/positions.js +29 -7
- package/dist/src/formats/gml/positions.js.map +1 -1
- package/dist/src/formats/gml/styles.d.ts.map +1 -1
- package/dist/src/formats/gml/styles.js +753 -101
- package/dist/src/formats/gml/styles.js.map +1 -1
- package/dist/src/formats/graphml/styles-plain.d.ts.map +1 -1
- package/dist/src/formats/graphml/styles-plain.js +6 -10
- package/dist/src/formats/graphml/styles-plain.js.map +1 -1
- package/dist/src/formats/graphml/styles-yed.d.ts +21 -15
- package/dist/src/formats/graphml/styles-yed.d.ts.map +1 -1
- package/dist/src/formats/graphml/styles-yed.js +692 -161
- package/dist/src/formats/graphml/styles-yed.js.map +1 -1
- package/dist/src/formats/graphml/styles-yfiles3.d.ts +1 -1
- package/dist/src/formats/graphml/styles-yfiles3.d.ts.map +1 -1
- package/dist/src/formats/graphml/styles-yfiles3.js +429 -64
- package/dist/src/formats/graphml/styles-yfiles3.js.map +1 -1
- package/dist/src/formats/graphml/yfiles.d.ts +3 -3
- package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
- package/dist/src/formats/graphml/yfiles.js +16 -6
- package/dist/src/formats/graphml/yfiles.js.map +1 -1
- package/dist/src/formats/json/dialect.d.ts +3 -2
- package/dist/src/formats/json/dialect.d.ts.map +1 -1
- package/dist/src/formats/json/dialect.js +39 -5
- package/dist/src/formats/json/dialect.js.map +1 -1
- package/dist/src/formats/json/importer.d.ts +13 -2
- package/dist/src/formats/json/importer.d.ts.map +1 -1
- package/dist/src/formats/json/importer.js +42 -6
- package/dist/src/formats/json/importer.js.map +1 -1
- package/dist/src/formats/json/index.d.ts +1 -1
- package/dist/src/formats/json/index.d.ts.map +1 -1
- package/dist/src/formats/json/index.js +1 -1
- package/dist/src/formats/json/index.js.map +1 -1
- package/dist/src/formats/json/positions.d.ts +5 -2
- package/dist/src/formats/json/positions.d.ts.map +1 -1
- package/dist/src/formats/json/positions.js +20 -4
- package/dist/src/formats/json/positions.js.map +1 -1
- package/dist/src/formats/json/styles.d.ts +12 -1
- package/dist/src/formats/json/styles.d.ts.map +1 -1
- package/dist/src/formats/json/styles.js +1755 -136
- package/dist/src/formats/json/styles.js.map +1 -1
- package/dist/src/formats/pajek/draw.d.ts +96 -0
- package/dist/src/formats/pajek/draw.d.ts.map +1 -0
- package/dist/src/formats/pajek/draw.js +372 -0
- package/dist/src/formats/pajek/draw.js.map +1 -0
- package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
- package/dist/src/formats/pajek/exporter.js +70 -51
- package/dist/src/formats/pajek/exporter.js.map +1 -1
- package/dist/src/formats/pajek/importer.d.ts +9 -0
- package/dist/src/formats/pajek/importer.d.ts.map +1 -1
- package/dist/src/formats/pajek/importer.js +233 -102
- package/dist/src/formats/pajek/importer.js.map +1 -1
- package/dist/src/formats/pajek/index.d.ts +1 -0
- package/dist/src/formats/pajek/index.d.ts.map +1 -1
- package/dist/src/formats/pajek/index.js.map +1 -1
- package/dist/src/formats/pajek/styles.d.ts +15 -7
- package/dist/src/formats/pajek/styles.d.ts.map +1 -1
- package/dist/src/formats/pajek/styles.js +1278 -114
- package/dist/src/formats/pajek/styles.js.map +1 -1
- package/dist/src/formats/pajek/syntax.d.ts +10 -1
- package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
- package/dist/src/formats/pajek/syntax.js +26 -2
- package/dist/src/formats/pajek/syntax.js.map +1 -1
- package/dist/src/formats/xgmml/emit.d.ts +1 -0
- package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
- package/dist/src/formats/xgmml/emit.js +65 -5
- package/dist/src/formats/xgmml/emit.js.map +1 -1
- package/dist/src/formats/xgmml/styles.d.ts +23 -3
- package/dist/src/formats/xgmml/styles.d.ts.map +1 -1
- package/dist/src/formats/xgmml/styles.js +277 -60
- package/dist/src/formats/xgmml/styles.js.map +1 -1
- package/dist/src/index.d.ts +4 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/positions/convert.d.ts.map +1 -1
- package/dist/src/positions/convert.js +11 -1
- package/dist/src/positions/convert.js.map +1 -1
- package/dist/src/positions/extract.d.ts.map +1 -1
- package/dist/src/positions/extract.js +53 -1
- package/dist/src/positions/extract.js.map +1 -1
- package/dist/src/positions/index.d.ts +1 -1
- package/dist/src/positions/index.d.ts.map +1 -1
- package/dist/src/positions/types.d.ts +59 -0
- package/dist/src/positions/types.d.ts.map +1 -1
- package/dist/src/sources/builtins.d.ts +1 -1
- package/dist/src/sources/builtins.d.ts.map +1 -1
- package/dist/src/sources/builtins.js +8 -2
- package/dist/src/sources/builtins.js.map +1 -1
- package/dist/src/sources/context.d.ts.map +1 -1
- package/dist/src/sources/context.js +1 -0
- package/dist/src/sources/context.js.map +1 -1
- package/dist/src/sources/cypher/descriptor.d.ts.map +1 -1
- package/dist/src/sources/cypher/descriptor.js +5 -0
- package/dist/src/sources/cypher/descriptor.js.map +1 -1
- package/dist/src/sources/cypher/index.d.ts.map +1 -1
- package/dist/src/sources/cypher/index.js +124 -18
- package/dist/src/sources/cypher/index.js.map +1 -1
- package/dist/src/sources/cypher/params.d.ts +1 -1
- package/dist/src/sources/cypher/params.d.ts.map +1 -1
- package/dist/src/sources/cypher/query-builder.d.ts +17 -0
- package/dist/src/sources/cypher/query-builder.d.ts.map +1 -1
- package/dist/src/sources/cypher/query-builder.js +31 -0
- package/dist/src/sources/cypher/query-builder.js.map +1 -1
- package/dist/src/sources/ids.d.ts +5 -0
- package/dist/src/sources/ids.d.ts.map +1 -1
- package/dist/src/sources/ids.js +5 -0
- package/dist/src/sources/ids.js.map +1 -1
- package/dist/src/sources/params.d.ts +3 -0
- package/dist/src/sources/params.d.ts.map +1 -1
- package/dist/src/sources/rest/descriptor.d.ts.map +1 -1
- package/dist/src/sources/rest/descriptor.js +5 -0
- package/dist/src/sources/rest/descriptor.js.map +1 -1
- package/dist/src/sources/rest/source.d.ts.map +1 -1
- package/dist/src/sources/rest/source.js +15 -0
- package/dist/src/sources/rest/source.js.map +1 -1
- package/dist/src/sources/sigv4.d.ts +5 -3
- package/dist/src/sources/sigv4.d.ts.map +1 -1
- package/dist/src/sources/sigv4.js +6 -4
- package/dist/src/sources/sigv4.js.map +1 -1
- package/dist/src/sources/sparql/descriptor.d.ts +10 -0
- package/dist/src/sources/sparql/descriptor.d.ts.map +1 -0
- package/dist/src/sources/sparql/descriptor.js +64 -0
- package/dist/src/sources/sparql/descriptor.js.map +1 -0
- package/dist/src/sources/sparql/index.d.ts +28 -0
- package/dist/src/sources/sparql/index.d.ts.map +1 -0
- package/dist/src/sources/sparql/index.js +314 -0
- package/dist/src/sources/sparql/index.js.map +1 -0
- package/dist/src/sources/sparql/ntriples.d.ts +69 -0
- package/dist/src/sources/sparql/ntriples.d.ts.map +1 -0
- package/dist/src/sources/sparql/ntriples.js +180 -0
- package/dist/src/sources/sparql/ntriples.js.map +1 -0
- package/dist/src/sources/sparql/params.d.ts +27 -0
- package/dist/src/sources/sparql/params.d.ts.map +1 -0
- package/dist/src/sources/sparql/params.js +5 -0
- package/dist/src/sources/sparql/params.js.map +1 -0
- package/dist/src/sources/sparql/query.d.ts +72 -0
- package/dist/src/sources/sparql/query.d.ts.map +1 -0
- package/dist/src/sources/sparql/query.js +113 -0
- package/dist/src/sources/sparql/query.js.map +1 -0
- package/dist/src/sources/types.d.ts +31 -0
- package/dist/src/sources/types.d.ts.map +1 -1
- package/dist/src/styles/annotations.d.ts +61 -5
- package/dist/src/styles/annotations.d.ts.map +1 -1
- package/dist/src/styles/annotations.js +130 -22
- package/dist/src/styles/annotations.js.map +1 -1
- package/dist/src/styles/canon/bends.d.ts +46 -0
- package/dist/src/styles/canon/bends.d.ts.map +1 -1
- package/dist/src/styles/canon/bends.js +123 -0
- package/dist/src/styles/canon/bends.js.map +1 -1
- package/dist/src/styles/canon/color-tables.d.ts +6 -1
- package/dist/src/styles/canon/color-tables.d.ts.map +1 -1
- package/dist/src/styles/canon/color-tables.js +10 -4
- package/dist/src/styles/canon/color-tables.js.map +1 -1
- package/dist/src/styles/canon/color.d.ts +3 -1
- package/dist/src/styles/canon/color.d.ts.map +1 -1
- package/dist/src/styles/canon/color.js +103 -3
- package/dist/src/styles/canon/color.js.map +1 -1
- package/dist/src/styles/canon/enums.d.ts +2 -2
- package/dist/src/styles/canon/enums.d.ts.map +1 -1
- package/dist/src/styles/canon/enums.js +81 -7
- package/dist/src/styles/canon/enums.js.map +1 -1
- package/dist/src/styles/canon/graphviz.d.ts +12 -3
- package/dist/src/styles/canon/graphviz.d.ts.map +1 -1
- package/dist/src/styles/canon/graphviz.js +57 -9
- package/dist/src/styles/canon/graphviz.js.map +1 -1
- package/dist/src/styles/canon/number.d.ts +8 -0
- package/dist/src/styles/canon/number.d.ts.map +1 -1
- package/dist/src/styles/canon/number.js +18 -0
- package/dist/src/styles/canon/number.js.map +1 -1
- package/dist/src/styles/canon/text.d.ts +29 -2
- package/dist/src/styles/canon/text.d.ts.map +1 -1
- package/dist/src/styles/canon/text.js +156 -16
- package/dist/src/styles/canon/text.js.map +1 -1
- package/dist/src/styles/codes.d.ts +2 -0
- package/dist/src/styles/codes.d.ts.map +1 -1
- package/dist/src/styles/codes.js +2 -0
- package/dist/src/styles/codes.js.map +1 -1
- package/dist/src/styles/cyjs/cascade.d.ts.map +1 -1
- package/dist/src/styles/cyjs/cascade.js +1015 -79
- package/dist/src/styles/cyjs/cascade.js.map +1 -1
- package/dist/src/styles/cyjs/defaults-table.d.ts.map +1 -1
- package/dist/src/styles/cyjs/defaults-table.js +3 -0
- package/dist/src/styles/cyjs/defaults-table.js.map +1 -1
- package/dist/src/styles/cyjs/emit.d.ts.map +1 -1
- package/dist/src/styles/cyjs/emit.js +202 -9
- package/dist/src/styles/cyjs/emit.js.map +1 -1
- package/dist/src/styles/cyjs/face.d.ts +20 -0
- package/dist/src/styles/cyjs/face.d.ts.map +1 -0
- package/dist/src/styles/cyjs/face.js +332 -0
- package/dist/src/styles/cyjs/face.js.map +1 -0
- package/dist/src/styles/cyjs/mappers.d.ts +44 -1
- package/dist/src/styles/cyjs/mappers.d.ts.map +1 -1
- package/dist/src/styles/cyjs/mappers.js +461 -26
- package/dist/src/styles/cyjs/mappers.js.map +1 -1
- package/dist/src/styles/cyjs/routes.d.ts +53 -0
- package/dist/src/styles/cyjs/routes.d.ts.map +1 -0
- package/dist/src/styles/cyjs/routes.js +360 -0
- package/dist/src/styles/cyjs/routes.js.map +1 -0
- package/dist/src/styles/cytoscape/charts.d.ts +23 -0
- package/dist/src/styles/cytoscape/charts.d.ts.map +1 -0
- package/dist/src/styles/cytoscape/charts.js +560 -0
- package/dist/src/styles/cytoscape/charts.js.map +1 -0
- package/dist/src/styles/cytoscape/emit.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/emit.js +156 -48
- package/dist/src/styles/cytoscape/emit.js.map +1 -1
- package/dist/src/styles/cytoscape/lexicon.d.ts +91 -3
- package/dist/src/styles/cytoscape/lexicon.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/lexicon.js +387 -77
- package/dist/src/styles/cytoscape/lexicon.js.map +1 -1
- package/dist/src/styles/cytoscape/mappings.d.ts +30 -0
- package/dist/src/styles/cytoscape/mappings.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/mappings.js +92 -0
- package/dist/src/styles/cytoscape/mappings.js.map +1 -1
- package/dist/src/styles/cytoscape/resolve.d.ts +42 -2
- package/dist/src/styles/cytoscape/resolve.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/resolve.js +623 -17
- package/dist/src/styles/cytoscape/resolve.js.map +1 -1
- package/dist/src/styles/defaults.d.ts +46 -26
- package/dist/src/styles/defaults.d.ts.map +1 -1
- package/dist/src/styles/defaults.js +308 -71
- package/dist/src/styles/defaults.js.map +1 -1
- package/dist/src/styles/index.d.ts +4 -3
- package/dist/src/styles/index.d.ts.map +1 -1
- package/dist/src/styles/index.js +3 -2
- package/dist/src/styles/index.js.map +1 -1
- package/dist/src/styles/internal.d.ts +1 -0
- package/dist/src/styles/internal.d.ts.map +1 -1
- package/dist/src/styles/internal.js +1 -0
- package/dist/src/styles/internal.js.map +1 -1
- package/dist/src/styles/io/generic.d.ts.map +1 -1
- package/dist/src/styles/io/generic.js +56 -16
- package/dist/src/styles/io/generic.js.map +1 -1
- package/dist/src/styles/io/round-trip.d.ts +56 -0
- package/dist/src/styles/io/round-trip.d.ts.map +1 -0
- package/dist/src/styles/io/round-trip.js +138 -0
- package/dist/src/styles/io/round-trip.js.map +1 -0
- package/dist/src/styles/io/writer.d.ts.map +1 -1
- package/dist/src/styles/io/writer.js +6 -1
- package/dist/src/styles/io/writer.js.map +1 -1
- package/dist/src/styles/notes.d.ts.map +1 -1
- package/dist/src/styles/notes.js +1 -0
- package/dist/src/styles/notes.js.map +1 -1
- package/dist/src/styles/plan/features.d.ts +1 -1
- package/dist/src/styles/plan/features.d.ts.map +1 -1
- package/dist/src/styles/plan/features.js +22 -2
- package/dist/src/styles/plan/features.js.map +1 -1
- package/dist/src/styles/plan/index.d.ts +1 -1
- package/dist/src/styles/plan/index.d.ts.map +1 -1
- package/dist/src/styles/plan/index.js +1 -1
- package/dist/src/styles/plan/index.js.map +1 -1
- package/dist/src/styles/plan/plan.d.ts.map +1 -1
- package/dist/src/styles/plan/plan.js +61 -4
- package/dist/src/styles/plan/plan.js.map +1 -1
- package/dist/src/styles/plan/resolve.d.ts +11 -0
- package/dist/src/styles/plan/resolve.d.ts.map +1 -1
- package/dist/src/styles/plan/resolve.js +40 -4
- package/dist/src/styles/plan/resolve.js.map +1 -1
- package/dist/src/styles/slots.d.ts +14 -0
- package/dist/src/styles/slots.d.ts.map +1 -0
- package/dist/src/styles/slots.js +20 -0
- package/dist/src/styles/slots.js.map +1 -0
- package/dist/src/styles/types.d.ts +622 -6
- package/dist/src/styles/types.d.ts.map +1 -1
- package/dist/src/styles/vocabulary.d.ts +3 -2
- package/dist/src/styles/vocabulary.d.ts.map +1 -1
- package/dist/src/styles/vocabulary.js +203 -0
- package/dist/src/styles/vocabulary.js.map +1 -1
- package/dist/styles.js +30 -239
- package/dist/styles.js.map +1 -1
- package/dist/xgmml.js +3 -3
- package/package.json +27 -7
- package/src/formats/cx/importer.ts +6 -1
- package/src/formats/cx/styles.ts +143 -9
- package/src/formats/cx2/importer.ts +1 -0
- package/src/formats/cx2/styles.ts +3 -1
- package/src/formats/cys/importer.ts +1 -0
- package/src/formats/cys/styles.ts +27 -5
- package/src/formats/dot/drawing.ts +799 -0
- package/src/formats/dot/importer.ts +120 -35
- package/src/formats/dot/label-places.ts +228 -0
- package/src/formats/dot/record.ts +336 -0
- package/src/formats/dot/styles.ts +1654 -153
- package/src/formats/gexf/dialog-metrics.ts +61 -0
- package/src/formats/gexf/importer.ts +50 -5
- package/src/formats/gexf/preview.ts +217 -0
- package/src/formats/gexf/schema.ts +2 -1
- package/src/formats/gexf/styles.ts +1099 -245
- package/src/formats/gml/importer.ts +291 -76
- package/src/formats/gml/index.ts +1 -1
- package/src/formats/gml/positions.ts +29 -7
- package/src/formats/gml/styles.ts +851 -109
- package/src/formats/graphml/styles-plain.ts +6 -15
- package/src/formats/graphml/styles-yed.ts +762 -173
- package/src/formats/graphml/styles-yfiles3.ts +485 -63
- package/src/formats/graphml/yfiles.ts +19 -6
- package/src/formats/json/dialect.ts +41 -5
- package/src/formats/json/importer.ts +59 -7
- package/src/formats/json/index.ts +1 -0
- package/src/formats/json/positions.ts +22 -5
- package/src/formats/json/styles.ts +2041 -185
- package/src/formats/pajek/draw.ts +458 -0
- package/src/formats/pajek/exporter.ts +81 -49
- package/src/formats/pajek/importer.ts +278 -103
- package/src/formats/pajek/index.ts +1 -0
- package/src/formats/pajek/styles.ts +1381 -133
- package/src/formats/pajek/syntax.ts +27 -2
- package/src/formats/xgmml/emit.ts +73 -5
- package/src/formats/xgmml/styles.ts +330 -71
- package/src/index.ts +5 -1
- package/src/positions/convert.ts +12 -1
- package/src/positions/extract.ts +55 -1
- package/src/positions/index.ts +1 -0
- package/src/positions/types.ts +60 -0
- package/src/sources/builtins.ts +8 -1
- package/src/sources/context.ts +1 -0
- package/src/sources/cypher/descriptor.ts +7 -1
- package/src/sources/cypher/index.ts +148 -18
- package/src/sources/cypher/params.ts +1 -1
- package/src/sources/cypher/query-builder.ts +33 -0
- package/src/sources/ids.ts +6 -0
- package/src/sources/params.ts +3 -0
- package/src/sources/rest/descriptor.ts +5 -0
- package/src/sources/rest/source.ts +16 -0
- package/src/sources/sigv4.ts +6 -4
- package/src/sources/sparql/descriptor.ts +67 -0
- package/src/sources/sparql/index.ts +356 -0
- package/src/sources/sparql/ntriples.ts +219 -0
- package/src/sources/sparql/params.ts +28 -0
- package/src/sources/sparql/query.ts +162 -0
- package/src/sources/types.ts +35 -0
- package/src/styles/annotations.ts +201 -27
- package/src/styles/canon/bends.ts +137 -0
- package/src/styles/canon/color-tables.ts +10 -4
- package/src/styles/canon/color.ts +105 -3
- package/src/styles/canon/enums.ts +98 -8
- package/src/styles/canon/graphviz.ts +71 -10
- package/src/styles/canon/number.ts +19 -0
- package/src/styles/canon/text.ts +187 -16
- package/src/styles/codes.ts +2 -0
- package/src/styles/cyjs/cascade.ts +1160 -84
- package/src/styles/cyjs/defaults-table.ts +3 -0
- package/src/styles/cyjs/emit.ts +233 -13
- package/src/styles/cyjs/face.ts +372 -0
- package/src/styles/cyjs/mappers.ts +492 -27
- package/src/styles/cyjs/routes.ts +432 -0
- package/src/styles/cytoscape/charts.ts +684 -0
- package/src/styles/cytoscape/emit.ts +170 -48
- package/src/styles/cytoscape/lexicon.ts +431 -78
- package/src/styles/cytoscape/mappings.ts +108 -0
- package/src/styles/cytoscape/resolve.ts +741 -17
- package/src/styles/defaults.ts +417 -108
- package/src/styles/index.ts +5 -0
- package/src/styles/internal.ts +1 -0
- package/src/styles/io/generic.ts +79 -23
- package/src/styles/io/round-trip.ts +202 -0
- package/src/styles/io/writer.ts +6 -1
- package/src/styles/notes.ts +1 -0
- package/src/styles/plan/features.ts +23 -2
- package/src/styles/plan/index.ts +1 -1
- package/src/styles/plan/plan.ts +69 -5
- package/src/styles/plan/resolve.ts +47 -4
- package/src/styles/slots.ts +25 -0
- package/src/styles/types.ts +633 -5
- package/src/styles/vocabulary.ts +211 -2
- package/dist/chunks/block-Cu22ewuS.js.map +0 -1
- package/dist/chunks/choose-Cdx6Enl2.js +0 -57
- package/dist/chunks/choose-Cdx6Enl2.js.map +0 -1
- package/dist/chunks/codes-CV_Bhcyi.js.map +0 -1
- package/dist/chunks/convert-BcQ8_jMo.js.map +0 -1
- package/dist/chunks/credentials-BiQsnMTb.js.map +0 -1
- package/dist/chunks/descriptor-BJ-W0Jd-.js.map +0 -1
- package/dist/chunks/emit-CD8xnY8s.js.map +0 -1
- package/dist/chunks/export-CZ7VRm4I.js.map +0 -1
- package/dist/chunks/exporter-bxxjOrDZ.js.map +0 -1
- package/dist/chunks/format-BMS-1Nxb.js +0 -64
- package/dist/chunks/format-BMS-1Nxb.js.map +0 -1
- package/dist/chunks/generic-CP6YD34u.js.map +0 -1
- package/dist/chunks/importer-B87_fmVx.js.map +0 -1
- package/dist/chunks/importer-CB_zV5_L.js.map +0 -1
- package/dist/chunks/importer-CVT-JyDE.js.map +0 -1
- package/dist/chunks/importer-Cyy6UseH.js.map +0 -1
- package/dist/chunks/importer-DPZDN40-.js.map +0 -1
- package/dist/chunks/importer-e3huMZbm.js.map +0 -1
- package/dist/chunks/lexicon-u2SI5xcx.js.map +0 -1
- package/dist/chunks/sigv4-LkAzsLAu.js.map +0 -1
- package/dist/chunks/styles-CaABMoO1.js.map +0 -1
- package/dist/chunks/styles-P_gmFAOi.js +0 -770
- package/dist/chunks/styles-P_gmFAOi.js.map +0 -1
- package/dist/chunks/styles-yed-Cs1nmrjn.js.map +0 -1
- package/dist/chunks/writer-DvHTl36J.js +0 -449
- 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,
|
package/src/positions/convert.ts
CHANGED
|
@@ -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);
|
package/src/positions/extract.ts
CHANGED
|
@@ -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
|
package/src/positions/index.ts
CHANGED
package/src/positions/types.ts
CHANGED
|
@@ -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). */
|
package/src/sources/builtins.ts
CHANGED
|
@@ -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
|
|
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
|
}
|
package/src/sources/context.ts
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
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
|
|
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
|
-
*
|
|
272
|
-
*
|
|
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
|
|
275
|
-
|
|
276
|
-
const
|
|
277
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
+
}
|
package/src/sources/ids.ts
CHANGED
|
@@ -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
|