@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.
- package/dist/chunks/{approximations-C2riR4NT.js → approximations-BRXsll0T.js} +2 -2
- package/dist/chunks/{approximations-C2riR4NT.js.map → approximations-BRXsll0T.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-yl0f_qLO.js} +931 -164
- package/dist/chunks/block-yl0f_qLO.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-DizmppHy.js} +5 -4
- package/dist/chunks/{context-cgmmOxZ2.js.map → context-DizmppHy.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-CmvJXYeH.js} +67 -16
- package/dist/chunks/credentials-CmvJXYeH.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-Dhez_Cew.js} +11 -2
- package/dist/chunks/descriptor-Dhez_Cew.js.map +1 -0
- package/dist/chunks/{emit-CD8xnY8s.js → emit-7Jkpg0yd.js} +1788 -133
- package/dist/chunks/emit-7Jkpg0yd.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-ChjL5fmP.js → exporter-1Ajud15J.js} +9 -8
- package/dist/chunks/{exporter-ChjL5fmP.js.map → exporter-1Ajud15J.js.map} +1 -1
- package/dist/chunks/{exporter-BIdaoIgh.js → exporter-B6yvL3wy.js} +7 -7
- package/dist/chunks/{exporter-BIdaoIgh.js.map → exporter-B6yvL3wy.js.map} +1 -1
- 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-DtVU80Fa.js → exporter-CA5q8ROP.js} +9 -8
- package/dist/chunks/{exporter-DtVU80Fa.js.map → exporter-CA5q8ROP.js.map} +1 -1
- package/dist/chunks/{exporter-bxxjOrDZ.js → exporter-CQQZFJ2v.js} +1284 -156
- package/dist/chunks/exporter-CQQZFJ2v.js.map +1 -0
- 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-Dc21MAdg.js} +387 -31
- package/dist/chunks/generic-Dc21MAdg.js.map +1 -0
- package/dist/chunks/{importer-B87_fmVx.js → importer-C6NVpCXp.js} +327 -84
- package/dist/chunks/importer-C6NVpCXp.js.map +1 -0
- package/dist/chunks/{importer-DPZDN40-.js → importer-CKFe4q54.js} +25 -17
- package/dist/chunks/importer-CKFe4q54.js.map +1 -0
- package/dist/chunks/{importer-Bji2MeWr.js → importer-CKbUbsJA.js} +13 -10
- package/dist/chunks/{importer-Bji2MeWr.js.map → importer-CKbUbsJA.js.map} +1 -1
- package/dist/chunks/{importer-CB_zV5_L.js → importer-ClCsdgTJ.js} +208 -1104
- package/dist/chunks/importer-ClCsdgTJ.js.map +1 -0
- package/dist/chunks/{importer-e3huMZbm.js → importer-CyVZTrf0.js} +14 -10
- package/dist/chunks/importer-CyVZTrf0.js.map +1 -0
- package/dist/chunks/{importer-CVT-JyDE.js → importer-DgG4v1Ms.js} +1537 -355
- package/dist/chunks/importer-DgG4v1Ms.js.map +1 -0
- package/dist/chunks/{importer-Cyy6UseH.js → importer-asFUrIsj.js} +66 -13
- package/dist/chunks/importer-asFUrIsj.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-IVRq2Uoo.js} +282 -74
- package/dist/chunks/lexicon-IVRq2Uoo.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-Cy3_SHRZ.js +79 -0
- package/dist/chunks/round-trip-Cy3_SHRZ.js.map +1 -0
- package/dist/chunks/{sigv4-LkAzsLAu.js → sigv4-BXwVbza3.js} +5 -5
- package/dist/chunks/sigv4-BXwVbza3.js.map +1 -0
- package/dist/chunks/{styles-CaABMoO1.js → styles-CAVmBLgp.js} +1237 -138
- package/dist/chunks/styles-CAVmBLgp.js.map +1 -0
- package/dist/chunks/styles-CPczw1Jz.js +1928 -0
- package/dist/chunks/styles-CPczw1Jz.js.map +1 -0
- package/dist/chunks/styles-boK6Ln54.js +2847 -0
- package/dist/chunks/styles-boK6Ln54.js.map +1 -0
- package/dist/chunks/{styles-yed-Cs1nmrjn.js → styles-yed-XeFBQ6VS.js} +506 -175
- package/dist/chunks/styles-yed-XeFBQ6VS.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 +8 -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 +848 -194
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +230 -193
- 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 +141 -23
- package/dist/sources-cypher.js.map +1 -1
- package/dist/sources-ndex.js +2 -2
- package/dist/sources-rest.js +32 -6
- package/dist/sources-rest.js.map +1 -1
- package/dist/sources-sparql.d.ts +1 -0
- package/dist/sources-sparql.js +439 -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/exporter.d.ts.map +1 -1
- package/dist/src/formats/dot/exporter.js +34 -2
- package/dist/src/formats/dot/exporter.js.map +1 -1
- package/dist/src/formats/dot/importer.d.ts +6 -1
- package/dist/src/formats/dot/importer.d.ts.map +1 -1
- package/dist/src/formats/dot/importer.js +170 -33
- package/dist/src/formats/dot/importer.js.map +1 -1
- package/dist/src/formats/dot/index.d.ts +3 -1
- package/dist/src/formats/dot/index.d.ts.map +1 -1
- package/dist/src/formats/dot/index.js +2 -1
- package/dist/src/formats/dot/index.js.map +1 -1
- package/dist/src/formats/dot/label-places.d.ts +41 -0
- package/dist/src/formats/dot/label-places.d.ts.map +1 -0
- package/dist/src/formats/dot/label-places.js +185 -0
- package/dist/src/formats/dot/label-places.js.map +1 -0
- package/dist/src/formats/dot/names.d.ts +13 -0
- package/dist/src/formats/dot/names.d.ts.map +1 -1
- package/dist/src/formats/dot/names.js +13 -0
- package/dist/src/formats/dot/names.js.map +1 -1
- 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 +72 -2
- package/dist/src/formats/dot/styles.d.ts.map +1 -1
- package/dist/src/formats/dot/styles.js +1500 -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 +754 -102
- 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 +695 -164
- 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 +431 -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 +1843 -136
- package/dist/src/formats/json/styles.js.map +1 -1
- package/dist/src/formats/pajek/draw.d.ts +104 -0
- package/dist/src/formats/pajek/draw.d.ts.map +1 -0
- package/dist/src/formats/pajek/draw.js +382 -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 +1395 -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 +6 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -5
- 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/credentials.d.ts +50 -1
- package/dist/src/sources/credentials.d.ts.map +1 -1
- package/dist/src/sources/credentials.js +69 -0
- package/dist/src/sources/credentials.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 +125 -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 +9 -0
- package/dist/src/sources/rest/descriptor.js.map +1 -1
- package/dist/src/sources/rest/openalex.d.ts +4 -2
- package/dist/src/sources/rest/openalex.d.ts.map +1 -1
- package/dist/src/sources/rest/openalex.js +4 -2
- package/dist/src/sources/rest/openalex.js.map +1 -1
- package/dist/src/sources/rest/source.d.ts.map +1 -1
- package/dist/src/sources/rest/source.js +38 -0
- package/dist/src/sources/rest/source.js.map +1 -1
- package/dist/src/sources/run.d.ts +2 -0
- package/dist/src/sources/run.d.ts.map +1 -1
- package/dist/src/sources/run.js +30 -3
- package/dist/src/sources/run.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 +327 -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 +73 -0
- package/dist/src/sources/sparql/query.d.ts.map +1 -0
- package/dist/src/sources/sparql/query.js +164 -0
- package/dist/src/sources/sparql/query.js.map +1 -0
- package/dist/src/sources/types.d.ts +60 -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 +89 -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 +1139 -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 +4 -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 +232 -10
- 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 +475 -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 +687 -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 +224 -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/exporter.ts +37 -1
- package/src/formats/dot/importer.ts +192 -36
- package/src/formats/dot/index.ts +3 -1
- package/src/formats/dot/label-places.ts +241 -0
- package/src/formats/dot/names.ts +15 -0
- package/src/formats/dot/record.ts +336 -0
- package/src/formats/dot/styles.ts +1702 -149
- 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 +852 -110
- package/src/formats/graphml/styles-plain.ts +6 -15
- package/src/formats/graphml/styles-yed.ts +765 -176
- package/src/formats/graphml/styles-yfiles3.ts +487 -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 +2123 -171
- package/src/formats/pajek/draw.ts +469 -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 +1506 -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 +12 -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/credentials.ts +90 -1
- package/src/sources/cypher/descriptor.ts +7 -1
- package/src/sources/cypher/index.ts +149 -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 +9 -0
- package/src/sources/rest/openalex.ts +4 -2
- package/src/sources/rest/source.ts +41 -0
- package/src/sources/run.ts +35 -3
- package/src/sources/sigv4.ts +6 -4
- package/src/sources/sparql/descriptor.ts +67 -0
- package/src/sources/sparql/index.ts +371 -0
- package/src/sources/sparql/ntriples.ts +219 -0
- package/src/sources/sparql/params.ts +28 -0
- package/src/sources/sparql/query.ts +216 -0
- package/src/sources/types.ts +68 -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 +107 -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 +1303 -84
- package/src/styles/cyjs/defaults-table.ts +4 -0
- package/src/styles/cyjs/emit.ts +268 -14
- package/src/styles/cyjs/face.ts +372 -0
- package/src/styles/cyjs/mappers.ts +506 -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 +698 -5
- package/src/styles/vocabulary.ts +232 -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/dist/graphml.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { G, a } from "./chunks/constants-
|
|
2
|
-
import { g, a as a2 } from "./chunks/importer-
|
|
3
|
-
import { G as G2 } from "./chunks/styles-yed-
|
|
1
|
+
import { G, a } from "./chunks/constants-CKkYLPtt.js";
|
|
2
|
+
import { g, a as a2 } from "./chunks/importer-C6NVpCXp.js";
|
|
3
|
+
import { G as G2 } from "./chunks/styles-yed-XeFBQ6VS.js";
|
|
4
4
|
export {
|
|
5
5
|
G as GRAPHML_ISSUE,
|
|
6
6
|
a as GRAPHML_LOSS,
|
package/dist/json.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { J, a, b, d, j, c, e, f } from "./chunks/exporter-
|
|
1
|
+
import { J, a, b, d, j, c, e, f, s } from "./chunks/exporter-CQQZFJ2v.js";
|
|
2
2
|
export {
|
|
3
3
|
J as JSON_DIALECTS,
|
|
4
4
|
a as JSON_ISSUE,
|
|
@@ -7,6 +7,7 @@ export {
|
|
|
7
7
|
j as jsonCapabilities,
|
|
8
8
|
c as jsonExporter,
|
|
9
9
|
e as jsonImporter,
|
|
10
|
-
f as jsonShapeOf
|
|
10
|
+
f as jsonShapeOf,
|
|
11
|
+
s as sniffJsonDialect
|
|
11
12
|
};
|
|
12
13
|
//# sourceMappingURL=json.js.map
|
package/dist/neo4j.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { f as DANGLING_REFERENCE_CODE$1, R as ROLE_TAKEN_CODE$1, I as ID_MERGED_CODE$1, k as DUPLICATE_NODE_CODE$1, n as MISSING_ENDPOINT_CODE$1, o as MISSING_ID_CODE$1, K as ImportReportBuilder, p as plural, a as agree, ah as ImportError, P as PRECISION_CODE, ai as withArticle, aj as ID_TEXT_COLLISION_CODE, A as ID_TEXT_TYPE_CODE, S as SINK_OPTION_CODE, O as OPTION_IGNORED_CODE, C as COLUMN_RENAMED_CODE, U as UNKNOWN_ATTR_TYPE_CODE, s as UNKNOWN_ENCODING_CODE, t as ENCODING_FALLBACK_CODE, u as INVALID_ENCODING_CODE, v as INVALID_UTF8_CODE, x as COLUMN_TYPE_CODE, y as ELEMENT_ISSUE, z as INPUT_ISSUE, ak as WEIGHT_KEY_CLASH_CODE, F as ROLE_DROPPED_CODE, al as MUTUAL_EXPANDED_CODE } from "./chunks/report-
|
|
2
|
-
import { c as checkRecordSyntax, R as RecordReader, B as BAD_QUOTE_CODE, U as UNCLOSED_QUOTE_CODE } from "./chunks/records-
|
|
1
|
+
import { f as DANGLING_REFERENCE_CODE$1, R as ROLE_TAKEN_CODE$1, I as ID_MERGED_CODE$1, k as DUPLICATE_NODE_CODE$1, n as MISSING_ENDPOINT_CODE$1, o as MISSING_ID_CODE$1, K as ImportReportBuilder, p as plural, a as agree, ah as ImportError, P as PRECISION_CODE, ai as withArticle, aj as ID_TEXT_COLLISION_CODE, A as ID_TEXT_TYPE_CODE, S as SINK_OPTION_CODE, O as OPTION_IGNORED_CODE, C as COLUMN_RENAMED_CODE, U as UNKNOWN_ATTR_TYPE_CODE, s as UNKNOWN_ENCODING_CODE, t as ENCODING_FALLBACK_CODE, u as INVALID_ENCODING_CODE, v as INVALID_UTF8_CODE, x as COLUMN_TYPE_CODE, y as ELEMENT_ISSUE, z as INPUT_ISSUE, ak as WEIGHT_KEY_CLASH_CODE, F as ROLE_DROPPED_CODE, al as MUTUAL_EXPANDED_CODE } from "./chunks/report-CwMfYa9J.js";
|
|
2
|
+
import { c as checkRecordSyntax, R as RecordReader, B as BAD_QUOTE_CODE, U as UNCLOSED_QUOTE_CODE } from "./chunks/records-NJiYvekn.js";
|
|
3
3
|
import { GraphFormatError, INVALID_INDEX } from "@graphty/graph-format";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { b as resolveImportOptions, f as reportSinkOptions, d as reportUnusedOptions, I as IdCoercer, l as declareAttribute, K as declareOn, u as uniqueColumnName, M as takenIn, R as RENAMED_CODE, p as parseWeightText, s as losesPrecision, m as parseDeclaredTemporal, q as parseDeclaredValue, n as declareCompanion, v as splitListText, N as parseTemporal, c as capabilities, r as resolveExportOptions, a as checkCapabilities, L as LOSS, B as mapDeclaredType, e as explicitWeights, F as isCanonicalIntegerText, E as formatTemporal } from "./chunks/export-Cha4dRFz.js";
|
|
5
|
+
import { D as DirectionResolver, p as pairFolding, c as formatInteger, a as formatF64, f as formatF32 } from "./chunks/format-BXiAb-1h.js";
|
|
6
|
+
import { g as quoteCsvCell } from "./chunks/escape-CuCIzNMB.js";
|
|
7
7
|
import { j as joinText, e as encodeChunks } from "./chunks/writer-DxjgHwSe.js";
|
|
8
|
-
import { b as throwIfAborted, i as isImportInput,
|
|
8
|
+
import { b as throwIfAborted, i as isImportInput, d as inputLength } from "./chunks/input-CAxt_aV-.js";
|
|
9
9
|
const STRUCTURAL = /* @__PURE__ */ new Set(["ID", "LABEL", "START_ID", "END_ID", "TYPE", "IGNORE"]);
|
|
10
10
|
const SPACE_KINDS = /* @__PURE__ */ new Set(["ID", "START_ID", "END_ID"]);
|
|
11
11
|
const HEADER_MARKER = /^[^:{}()]*:\s*(ID|START_ID|END_ID)\s*(\(|\{|$)/i;
|
package/dist/obo.js
CHANGED
package/dist/pajek.js
CHANGED
package/dist/positions.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as toNeutral, m as median } from "./chunks/convert-
|
|
2
|
-
import { f, a, w } from "./chunks/convert-
|
|
1
|
+
import { t as toNeutral, m as median } from "./chunks/convert-Ct2zelbQ.js";
|
|
2
|
+
import { f, a, w } from "./chunks/convert-Ct2zelbQ.js";
|
|
3
3
|
import { t as toolOf } from "./chunks/units-XMZFIFe1.js";
|
|
4
4
|
const POSITION_ISSUE = Object.freeze({
|
|
5
5
|
/** Every placed node sits on one point; the coordinates are dropped and `usable` is false. */
|
|
@@ -88,6 +88,11 @@ function extractPositions(importer, snapshot, report, options = {}) {
|
|
|
88
88
|
const coords = readRows(n, spelling, notes);
|
|
89
89
|
signal?.throwIfAborted();
|
|
90
90
|
const containers = containersOf(snapshot);
|
|
91
|
+
if (spelling.extra.containersFollowChildren === true) {
|
|
92
|
+
for (const row of containers) {
|
|
93
|
+
coords.values.fill(Number.NaN, 3 * row, 3 * row + 3);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
91
96
|
const groups = applyGroups(spelling, coords);
|
|
92
97
|
collectGroups(spelling, coords, containers, groups);
|
|
93
98
|
const { placed, total } = countPlaced(coords, containers, notes);
|
|
@@ -103,6 +108,7 @@ function extractPositions(importer, snapshot, report, options = {}) {
|
|
|
103
108
|
},
|
|
104
109
|
units: spelling.extra.units ?? "file",
|
|
105
110
|
...spelling.extra.pxPerUnit === void 0 ? {} : { pxPerUnit: spelling.extra.pxPerUnit },
|
|
111
|
+
...spelling.extra.viewerFit === void 0 ? {} : { viewerFit: spelling.extra.viewerFit },
|
|
106
112
|
medianNodeSize: spelling.medianNodeSize ?? medianSize(spelling.size, n, containers),
|
|
107
113
|
dims: coords.realZ ? 3 : 2,
|
|
108
114
|
coords: coords.values,
|
|
@@ -121,11 +127,27 @@ function spellingOf(importer, snapshot, signal) {
|
|
|
121
127
|
}
|
|
122
128
|
const column = hook?.column === void 0 ? snapshot.nodes.byRole("position") : snapshot.nodes.get(hook.column);
|
|
123
129
|
if (column === null || column.meta.components < 2) {
|
|
124
|
-
return null;
|
|
130
|
+
return hook?.unplacedCircle === void 0 ? null : circleSpelling(snapshot, hook);
|
|
125
131
|
}
|
|
126
132
|
const extra = { ...extraOf(column.meta.extra), ...extraOf(hook ?? {}) };
|
|
127
133
|
return { read: vectorReader(column), size: sizeReader(snapshot, extra), extra, ...hookFields(hook) };
|
|
128
134
|
}
|
|
135
|
+
function circleSpelling(snapshot, hook) {
|
|
136
|
+
const circle = hook.unplacedCircle;
|
|
137
|
+
const n = snapshot.nodeCount;
|
|
138
|
+
const read = (row, out) => {
|
|
139
|
+
if (circle === void 0 || n === 0) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
const a2 = (circle.startDegrees + circle.direction * 360 * row / n) * Math.PI / 180;
|
|
143
|
+
out[0] = circle.center[0] + circle.radius * Math.cos(a2);
|
|
144
|
+
out[1] = circle.center[1] + circle.radius * Math.sin(a2);
|
|
145
|
+
out[2] = 0;
|
|
146
|
+
return true;
|
|
147
|
+
};
|
|
148
|
+
const extra = { ...extraOf(hook), sourceDims: 2 };
|
|
149
|
+
return { read, size: sizeReader(snapshot, extra), extra, ...hookFields(hook) };
|
|
150
|
+
}
|
|
129
151
|
function plainSpelling(snapshot, hook) {
|
|
130
152
|
const x = snapshot.nodes.get(hook.x ?? "");
|
|
131
153
|
const y = snapshot.nodes.get(hook.y ?? "");
|
|
@@ -175,8 +197,15 @@ function extraOf(source) {
|
|
|
175
197
|
pick("width", (v) => typeof v === "string");
|
|
176
198
|
pick("height", (v) => typeof v === "string");
|
|
177
199
|
pick("pxPerUnit", (v) => typeof v === "number" && Number.isFinite(v) && v > 0);
|
|
200
|
+
pick("pxPerUnitY", (v) => typeof v === "number" && Number.isFinite(v) && v > 0);
|
|
178
201
|
pick("zOrigin", (v) => typeof v === "number" && Number.isFinite(v));
|
|
179
202
|
pick("zeroUnplaced", (v) => typeof v === "boolean");
|
|
203
|
+
pick("originUnplaced", (v) => typeof v === "boolean");
|
|
204
|
+
pick("containersFollowChildren", (v) => typeof v === "boolean");
|
|
205
|
+
const fit = extra.viewerFit;
|
|
206
|
+
if (typeof fit?.padding === "number" && Number.isFinite(fit.padding) && fit.padding >= 0) {
|
|
207
|
+
out.viewerFit = { padding: fit.padding };
|
|
208
|
+
}
|
|
180
209
|
return out;
|
|
181
210
|
}
|
|
182
211
|
function readRows(n, spelling, notes) {
|
|
@@ -195,10 +224,23 @@ function readRows(n, spelling, notes) {
|
|
|
195
224
|
if (spelling.extra.zeroUnplaced === true) {
|
|
196
225
|
dropZeroPile(values);
|
|
197
226
|
}
|
|
227
|
+
if (spelling.extra.originUnplaced === true) {
|
|
228
|
+
placeUnplacedAtOrigin(values);
|
|
229
|
+
}
|
|
198
230
|
const realZ = spelling.extra.sourceDims === 3 && !constantZ(values);
|
|
199
231
|
convertRows(values, spelling.extra, spelling.size, realZ, notes);
|
|
200
232
|
return { values, realZ };
|
|
201
233
|
}
|
|
234
|
+
function placeUnplacedAtOrigin(values) {
|
|
235
|
+
if (!values.some((v) => !Number.isNaN(v))) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
for (let i = 0; i < values.length; i += 3) {
|
|
239
|
+
if (Number.isNaN(values[i])) {
|
|
240
|
+
values.fill(0, i, i + 3);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
202
244
|
function convertRows(values, extra, size, realZ, notes) {
|
|
203
245
|
const p = [0, 0, 0];
|
|
204
246
|
for (let i = 0; i < values.length; i += 3) {
|
package/dist/positions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"positions.js","sources":["../src/positions/codes.ts","../src/common/notes.ts","../src/positions/extract.ts"],"sourcesContent":["/**\n * The note codes of `extractPositions()`. Singular `W_POSITION_*` codes are about some nodes,\n * plural `W_POSITIONS_*` codes about the file as a whole. Keys drop the `W_` and `POSITION_` /\n * `POSITIONS_` prefixes.\n */\n\n/**\n * Every code a `PositionNote` carries.\n * @category Positions\n */\nexport const POSITION_ISSUE = Object.freeze({\n /** Every placed node sits on one point; the coordinates are dropped and `usable` is false. */\n STACKED: \"W_POSITION_STACKED\",\n /** Some nodes have no position. */\n PARTIAL: \"W_POSITION_PARTIAL\",\n /** Some coordinates are not finite numbers; those nodes count as unplaced. */\n NON_FINITE: \"W_POSITION_NON_FINITE\",\n /** The file mixes 2- and 3-coordinate positions. */\n DIMS_MIXED: \"W_POSITION_DIMS_MIXED\",\n /** A top-left coordinate has no width or height, so it was not moved to the center. */\n ANCHOR_NO_SIZE: \"W_POSITION_ANCHOR_NO_SIZE\",\n /** The file holds more than one view (layout); only the first is used. */\n OTHER_VIEWS: \"W_POSITION_OTHER_VIEWS\",\n /** The file has position-like columns this format does not read (plain `x` / `y`). */\n NOT_READ: \"W_POSITIONS_NOT_READ\",\n} as const);\n\n/**\n * A code of `POSITION_ISSUE`.\n * @category Positions\n */\nexport type PositionNoteCode = (typeof POSITION_ISSUE)[keyof typeof POSITION_ISSUE];\n","/**\n * The note collector file positions use (and file styles, after their rebase): one note per code\n * (and optional property), never one per element, with at most 8 distinct samples of 80\n * characters, a total count and the element indexes the note covers.\n */\n\n/** At most this many samples per note. */\nconst MAX_SAMPLES = 8;\n/** A sample is cut to this many characters. */\nconst MAX_SAMPLE_LENGTH = 80;\n\n/** One occurrence (or `count` occurrences) of a condition. */\ninterface NoteReport {\n /** An example of the offending value. */\n readonly sample?: unknown;\n /** The element the report is about, by index. */\n readonly element?: number;\n /** How many occurrences the report stands for; defaults to 1. */\n readonly count?: number;\n}\n\n/** A collected note, before a module shapes it into its own note type. */\ninterface CollectedNote<C extends string> {\n readonly code: C;\n readonly property: string | null;\n readonly count: number;\n readonly samples: readonly string[];\n readonly elements: readonly number[] | { readonly count: number };\n}\n\ninterface Collecting<C extends string> {\n readonly code: C;\n readonly property: string | null;\n count: number;\n readonly samples: string[];\n readonly elements: Set<number>;\n unindexed: boolean;\n}\n\n/** Collects notes, aggregated per (code, property), in the order their conditions first occur. */\nexport class NoteCollector<C extends string> {\n readonly #notes = new Map<string, Collecting<C>>();\n\n /**\n * Record a condition.\n * @param code - the condition\n * @param report - a sample, the element index and a count\n * @param property - what the note is about, or null\n */\n add(code: C, report: NoteReport = {}, property: string | null = null): void {\n const key = `${code}\\u0000${property ?? \"\"}`;\n let note = this.#notes.get(key);\n if (note === undefined) {\n note = { code, property, count: 0, samples: [], elements: new Set(), unindexed: false };\n this.#notes.set(key, note);\n }\n note.count += report.count ?? 1;\n if (report.element === undefined) {\n note.unindexed = true;\n } else {\n note.elements.add(report.element);\n }\n if (report.sample !== undefined && note.samples.length < MAX_SAMPLES) {\n const sample = sampleText(report.sample);\n if (!note.samples.includes(sample)) {\n note.samples.push(sample);\n }\n }\n }\n\n /**\n * The collected notes.\n * @returns one note per (code, property)\n */\n list(): CollectedNote<C>[] {\n return Array.from(this.#notes.values(), (n) => ({\n code: n.code,\n property: n.property,\n count: n.count,\n samples: [...n.samples],\n elements: n.unindexed ? { count: n.count } : Array.from(n.elements).sort((a, b) => a - b),\n }));\n }\n}\n\n/**\n * A sample as at most 80 characters of text.\n * @param value - the sample\n * @returns the text\n */\nfunction sampleText(value: unknown): string {\n const text = typeof value === \"string\" ? value : (JSON.stringify(value) ?? String(value));\n return text.length > MAX_SAMPLE_LENGTH ? `${text.slice(0, MAX_SAMPLE_LENGTH - 3)}...` : text;\n}\n","/**\n * `extractPositions()`: any format's stored node coordinates in the neutral convention (center,\n * y up, the file's unit, 3 components). The snapshot's role-`position` column keeps the values the\n * file wrote; this reads them through the spelling the column's `meta.extra` (or the importer's\n * `positions()` hook) declares.\n */\n\nimport type { Column, GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { NoteCollector } from \"../common/notes.js\";\nimport { type GraphTool, toolOf } from \"../common/units.js\";\nimport type { GraphImporter, ImportReport } from \"../types.js\";\nimport { POSITION_ISSUE, type PositionNoteCode } from \"./codes.js\";\nimport { median, toNeutral } from \"./convert.js\";\nimport type {\n ExtractPositionsOptions,\n FilePositionGroup,\n FilePositions,\n ImporterGroupBox,\n ImporterPositions,\n PositionColumnExtra,\n PositionNote,\n} from \"./types.js\";\n\ntype Point = [number, number, number];\n\n/** Reads one row's raw coordinates into `out`; false when the row has none. */\ntype RowReader = (row: number, out: Point) => boolean;\n\n/** Reads one row's width and height; null when the row has no size. */\ntype SizeReader = (row: number) => readonly [number, number] | null;\n\n/** Where a file's coordinates are and how they are spelled. */\ninterface Spelling {\n readonly read: RowReader;\n /** Reads a row's width and height from the size columns the spelling names; null without both. */\n readonly size: SizeReader;\n readonly extra: PositionColumnExtra;\n readonly groups: readonly ImporterGroupBox[];\n readonly medianNodeSize: number | null | undefined;\n readonly tool: GraphTool | null | undefined;\n}\n\n/** Report codes of format readers that mean the file mixes 2- and 3-coordinate positions. */\nconst DIMS_MIXED_CODES: ReadonlySet<string> = new Set([\"W_PAJEK_COORD_DIMS\", \"W_DOT_POS_DIMS\"]);\n\n/** graph-io's English for each note, for its own logs only. */\nconst PHRASES: Readonly<Record<PositionNoteCode, string>> = {\n W_POSITION_STACKED: \"every placed node is on one point; the positions were dropped\",\n W_POSITION_PARTIAL: \"nodes have no position\",\n W_POSITION_NON_FINITE: \"positions are not finite numbers\",\n W_POSITION_DIMS_MIXED: \"positions mix 2 and 3 coordinates\",\n W_POSITION_ANCHOR_NO_SIZE: \"top-left positions have no size and were not moved to the center\",\n W_POSITION_OTHER_VIEWS: \"other views were not used\",\n W_POSITIONS_NOT_READ: \"position-like columns this format does not read\",\n};\n\n/**\n * A file's stored node coordinates in the neutral convention: each node's center, y up, in the\n * file's own unit. Call it with the importer that read the snapshot and the report it returned.\n * @example\n * ```ts\n * const { snapshot, report } = await importGraph(text, { format: \"gml\" });\n * const positions = extractPositions(gmlImporter, snapshot, report);\n * if (positions?.usable) console.log(positions.coords.subarray(0, 3)); // node 0's x, y, z\n * ```\n * @param importer - the importer that read the snapshot (its `positions()` hook, when it has one, says how the coordinates are spelled)\n * @param snapshot - the imported graph\n * @param report - the import's report\n * @param options - `signal` to abort\n * @returns the positions, or null when the file stores none and has no position-like columns\n * @category Positions\n */\nexport function extractPositions(\n importer: GraphImporter,\n snapshot: GraphSnapshot,\n report: ImportReport,\n options: ExtractPositionsOptions = {},\n): FilePositions | null {\n const signal = options.signal ?? null;\n signal?.throwIfAborted();\n const notes = new NoteCollector<PositionNoteCode>();\n const spelling = spellingOf(importer, snapshot, signal);\n if (spelling === null) {\n noteUnread(snapshot, notes);\n return notes.list().length === 0 ? null : emptyPositions(importer, snapshot, notes);\n }\n const n = snapshot.nodeCount;\n const coords = readRows(n, spelling, notes);\n signal?.throwIfAborted();\n const containers = containersOf(snapshot);\n const groups = applyGroups(spelling, coords);\n collectGroups(spelling, coords, containers, groups);\n const { placed, total } = countPlaced(coords, containers, notes);\n const stacked = dropStacked(coords, placed, notes);\n noteReport(report, notes);\n noteOtherViews(snapshot, notes);\n return {\n version: 1,\n source: {\n format: importer.format,\n tool: spelling.tool ?? toolOf(snapshot.meta.creator),\n yAxis: spelling.extra.yAxis ?? \"up\",\n },\n units: spelling.extra.units ?? \"file\",\n ...(spelling.extra.pxPerUnit === undefined ? {} : { pxPerUnit: spelling.extra.pxPerUnit }),\n medianNodeSize: spelling.medianNodeSize ?? medianSize(spelling.size, n, containers),\n dims: coords.realZ ? 3 : 2,\n coords: coords.values,\n placed: stacked ? 0 : placed,\n total,\n usable: !stacked && placed > 0,\n bounds: stacked ? null : boundsOf(coords.values),\n groups,\n notes: noteList(notes),\n };\n}\n\n// ------------------------------------------------------------ spelling\n\n/**\n * Where the coordinates are: the importer's hook wins over the column's `meta.extra`.\n * @param importer - the importer\n * @param snapshot - the graph\n * @param signal - the abort signal\n * @returns the spelling, or null when the file stores no coordinates\n */\nfunction spellingOf(importer: GraphImporter, snapshot: GraphSnapshot, signal: AbortSignal | null): Spelling | null {\n const hook = importer.positions?.(snapshot, { signal }) ?? null;\n if (hook?.x !== undefined && hook.y !== undefined) {\n return plainSpelling(snapshot, hook);\n }\n const column = hook?.column === undefined ? snapshot.nodes.byRole(\"position\") : snapshot.nodes.get(hook.column);\n if (column === null || column.meta.components < 2) {\n return null;\n }\n const extra = { ...extraOf(column.meta.extra), ...extraOf(hook ?? {}) };\n return { read: vectorReader(column), size: sizeReader(snapshot, extra), extra, ...hookFields(hook) };\n}\n\n/**\n * The spelling of the simple hook form: plain x / y (/ z) columns.\n * @param snapshot - the graph\n * @param hook - the hook's answer\n * @returns the spelling, or null when a named column is missing\n */\nfunction plainSpelling(snapshot: GraphSnapshot, hook: ImporterPositions): Spelling | null {\n const x = snapshot.nodes.get(hook.x ?? \"\");\n const y = snapshot.nodes.get(hook.y ?? \"\");\n const z = hook.z === undefined ? null : snapshot.nodes.get(hook.z);\n if (x === null || y === null) {\n return null;\n }\n const read: RowReader = (row, out) => {\n if (!x.isSet(row) || !y.isSet(row)) {\n return false;\n }\n out[0] = Number(x.value(row));\n out[1] = Number(y.value(row));\n out[2] = z?.isSet(row) === true ? Number(z.value(row)) : 0;\n return true;\n };\n const extra = { ...extraOf(hook), sourceDims: z === null ? 2 : 3 } as const;\n return { read, size: sizeReader(snapshot, extra), extra, ...hookFields(hook) };\n}\n\n/**\n * The hook's fields beside the spelling.\n * @param hook - the hook's answer, or null\n * @returns groups, median node size and tool\n */\nfunction hookFields(hook: ImporterPositions | null): Pick<Spelling, \"groups\" | \"medianNodeSize\" | \"tool\"> {\n return { groups: hook?.groups ?? [], medianNodeSize: hook?.medianNodeSize, tool: hook?.tool };\n}\n\n/**\n * A reader over a 2- or 3-component column.\n * @param column - the column\n * @returns the reader\n */\nfunction vectorReader(column: Column): RowReader {\n return (row, out) => {\n if (!column.isSet(row)) {\n return false;\n }\n const v = column.value(row) as ArrayLike<number>;\n out[0] = v[0];\n out[1] = v[1];\n out[2] = v.length > 2 ? v[2] : 0;\n return true;\n };\n}\n\n/**\n * The spelling fields of an extra (or a hook's answer), each kept only when well formed.\n * @param source - a column's meta.extra or a hook's answer\n * @returns the fields\n */\nfunction extraOf(source: object): PositionColumnExtra {\n const extra = source as Readonly<Record<string, unknown>>;\n const out: Record<string, unknown> = {};\n const pick = (key: keyof PositionColumnExtra, ok: (v: unknown) => boolean): void => {\n if (ok(extra[key])) {\n out[key] = extra[key];\n }\n };\n pick(\"units\", (v) => v === \"px\" || v === \"file\");\n pick(\"sourceDims\", (v) => v === 2 || v === 3);\n pick(\"yAxis\", (v) => v === \"up\" || v === \"down\");\n pick(\"anchor\", (v) => v === \"center\" || v === \"top-left\");\n pick(\"width\", (v) => typeof v === \"string\");\n pick(\"height\", (v) => typeof v === \"string\");\n pick(\"pxPerUnit\", (v) => typeof v === \"number\" && Number.isFinite(v) && v > 0);\n pick(\"zOrigin\", (v) => typeof v === \"number\" && Number.isFinite(v));\n pick(\"zeroUnplaced\", (v) => typeof v === \"boolean\");\n return out;\n}\n\n// ------------------------------------------------------------ rows\n\n/** Coordinates by node index, with whether the file has a z that differs between nodes. */\ninterface Rows {\n readonly values: Float64Array;\n readonly realZ: boolean;\n}\n\n/**\n * Read every row and convert it to the neutral convention.\n * @param n - the node count\n * @param spelling - how the coordinates are spelled\n * @param notes - receives non-finite and anchor notes\n * @returns the coordinates (NaN rows have none)\n */\nfunction readRows(n: number, spelling: Spelling, notes: NoteCollector<PositionNoteCode>): Rows {\n const values = new Float64Array(3 * n).fill(Number.NaN);\n const p: Point = [0, 0, 0];\n for (let row = 0; row < n; row++) {\n if (!spelling.read(row, p)) {\n continue;\n }\n if (Number.isFinite(p[0]) && Number.isFinite(p[1]) && Number.isFinite(p[2])) {\n values.set(p, 3 * row);\n } else {\n notes.add(POSITION_ISSUE.NON_FINITE, { element: row, sample: p.join(\",\") });\n }\n }\n if (spelling.extra.zeroUnplaced === true) {\n dropZeroPile(values);\n }\n const realZ = spelling.extra.sourceDims === 3 && !constantZ(values);\n convertRows(values, spelling.extra, spelling.size, realZ, notes);\n return { values, realZ };\n}\n\n/**\n * Convert every placed row in place.\n * @param values - the raw coordinates\n * @param extra - the spelling\n * @param size - reads a row's width and height\n * @param realZ - whether z differs between nodes\n * @param notes - receives the anchor note\n */\nfunction convertRows(\n values: Float64Array,\n extra: PositionColumnExtra,\n size: SizeReader,\n realZ: boolean,\n notes: NoteCollector<PositionNoteCode>,\n): void {\n const p: Point = [0, 0, 0];\n for (let i = 0; i < values.length; i += 3) {\n if (Number.isNaN(values[i])) {\n continue;\n }\n const s = extra.anchor === \"top-left\" ? size(i / 3) : null;\n if (extra.anchor === \"top-left\" && s === null) {\n notes.add(POSITION_ISSUE.ANCHOR_NO_SIZE, { element: i / 3 });\n }\n p[0] = values[i];\n p[1] = values[i + 1];\n p[2] = values[i + 2];\n toNeutral(p, extra, s, realZ);\n values.set(p, i);\n }\n}\n\n/**\n * Reads a row's width and height from the size columns a spelling names.\n * @param snapshot - the graph\n * @param extra - the spelling\n * @returns the reader; it answers null for a row without both, or when the columns are missing\n */\nfunction sizeReader(snapshot: GraphSnapshot, extra: PositionColumnExtra): SizeReader {\n const w = extra.width === undefined ? null : snapshot.nodes.get(extra.width);\n const h = extra.height === undefined ? null : snapshot.nodes.get(extra.height);\n if (w === null || h === null) {\n return () => null;\n }\n return (row) => {\n if (!w.isSet(row) || !h.isSet(row)) {\n return null;\n }\n const size: [number, number] = [Number(w.value(row)), Number(h.value(row))];\n return Number.isFinite(size[0]) && Number.isFinite(size[1]) ? size : null;\n };\n}\n\n/**\n * NetworkX writes (0, 0) for a node with no position: when other rows are placed, an exact (0, 0)\n * shared by two or more rows counts as unplaced.\n * @param values - the raw coordinates, changed in place\n */\nfunction dropZeroPile(values: Float64Array): void {\n const zeros: number[] = [];\n let others = 0;\n for (let i = 0; i < values.length; i += 3) {\n if (values[i] === 0 && values[i + 1] === 0) {\n zeros.push(i);\n } else if (!Number.isNaN(values[i])) {\n others++;\n }\n }\n if (zeros.length >= 2 && others > 0) {\n for (const i of zeros) {\n values.fill(Number.NaN, i, i + 3);\n }\n }\n}\n\n/**\n * Whether every placed row has the same z (Pajek writes z = 0.5 on 2D drawings).\n * @param values - the raw coordinates\n * @returns true when z never differs\n */\nfunction constantZ(values: Float64Array): boolean {\n let z = Number.NaN;\n for (let i = 0; i < values.length; i += 3) {\n if (Number.isNaN(values[i])) {\n continue;\n }\n if (Number.isNaN(z)) {\n z = values[i + 2];\n } else if (values[i + 2] !== z) {\n return false;\n }\n }\n return true;\n}\n\n// ------------------------------------------------------------ groups\n\n/**\n * The nodes another node names as its parent: group containers.\n * @param snapshot - the graph\n * @returns the container indexes\n */\nfunction containersOf(snapshot: GraphSnapshot): Set<number> {\n const out = new Set<number>();\n const parent = snapshot.nodes.byRole(\"parent\");\n if (parent === null) {\n return out;\n }\n for (let row = 0; row < parent.length; row++) {\n const v = parent.isSet(row) ? parent.value(row) : undefined;\n if (typeof v === \"number\") {\n out.add(v);\n }\n }\n return out;\n}\n\n/**\n * The hook's group boxes in the neutral convention; a container with no coordinate of its own is\n * placed at its box's center.\n * @param spelling - the spelling and the hook's boxes\n * @param rows - the coordinates, changed in place\n * @returns the boxes\n */\nfunction applyGroups(spelling: Spelling, rows: Rows): FilePositionGroup[] {\n const out: FilePositionGroup[] = [];\n for (const { node, box } of spelling.groups) {\n const p: Point = [box.x, box.y, 0];\n toNeutral(p, spelling.extra, [box.width, box.height], false);\n if (Number.isNaN(rows.values[3 * node])) {\n rows.values.set(p, 3 * node);\n }\n if (!out.some((g) => g.node === node)) {\n out.push({ node, box: { x: p[0], y: p[1], width: box.width, height: box.height } });\n }\n }\n return out;\n}\n\n/**\n * Boxes for the containers the file gives a coordinate and a size (yEd groups).\n * @param spelling - the size reader\n * @param rows - the coordinates\n * @param containers - the container indexes\n * @param groups - receives the boxes\n */\nfunction collectGroups(\n spelling: Spelling,\n rows: Rows,\n containers: ReadonlySet<number>,\n groups: FilePositionGroup[],\n): void {\n for (const node of containers) {\n const size = spelling.size(node);\n const i = 3 * node;\n if (size !== null && !Number.isNaN(rows.values[i]) && !groups.some((g) => g.node === node)) {\n groups.push({ node, box: { x: rows.values[i], y: rows.values[i + 1], width: size[0], height: size[1] } });\n }\n }\n}\n\n// ------------------------------------------------------------ counts and notes\n\n/**\n * Count the placed rows and the rows that need a position; note the unplaced ones.\n * @param rows - the coordinates\n * @param containers - containers without a coordinate do not need one\n * @param notes - receives the partial note\n * @returns placed and total\n */\nfunction countPlaced(\n rows: Rows,\n containers: ReadonlySet<number>,\n notes: NoteCollector<PositionNoteCode>,\n): { placed: number; total: number } {\n const { values } = rows;\n const unplaced: number[] = [];\n let placed = 0;\n let total = 0;\n for (let row = 0; 3 * row < values.length; row++) {\n const has = !Number.isNaN(values[3 * row]);\n if (has) {\n placed++;\n } else if (!containers.has(row)) {\n unplaced.push(row);\n }\n total += has || !containers.has(row) ? 1 : 0;\n }\n if (placed > 0 && unplaced.length > 0) {\n for (const element of unplaced) {\n notes.add(POSITION_ISSUE.PARTIAL, { element });\n }\n }\n return { placed, total };\n}\n\n/**\n * Drop the coordinates when every placed node sits on one point.\n * @param rows - the coordinates, cleared in place when stacked\n * @param placed - the placed count\n * @param notes - receives the stacked note\n * @returns whether they were stacked\n */\nfunction dropStacked(rows: Rows, placed: number, notes: NoteCollector<PositionNoteCode>): boolean {\n if (placed < 2) {\n return false;\n }\n const { values } = rows;\n let first = -1;\n for (let i = 0; i < values.length; i += 3) {\n if (Number.isNaN(values[i])) {\n continue;\n }\n if (first < 0) {\n first = i;\n } else if (\n values[i] !== values[first] ||\n values[i + 1] !== values[first + 1] ||\n values[i + 2] !== values[first + 2]\n ) {\n return false;\n }\n }\n notes.add(POSITION_ISSUE.STACKED, {\n count: placed,\n sample: Array.from(values.subarray(first, first + 3)).join(\",\"),\n });\n values.fill(Number.NaN);\n return true;\n}\n\n/**\n * Lift the format readers' mixed-dimension warnings into the shared code.\n * @param report - the import report\n * @param notes - receives the note\n */\nfunction noteReport(report: ImportReport, notes: NoteCollector<PositionNoteCode>): void {\n for (const issue of report.issues) {\n if (DIMS_MIXED_CODES.has(issue.code)) {\n notes.add(POSITION_ISSUE.DIMS_MIXED, { sample: issue.code });\n }\n }\n}\n\n/**\n * Note the extra view columns of a CX file (`position@2`, ...): only the first view is used.\n * @param snapshot - the graph\n * @param notes - receives the note\n */\nfunction noteOtherViews(snapshot: GraphSnapshot, notes: NoteCollector<PositionNoteCode>): void {\n for (const column of snapshot.nodes) {\n if (/^position@\\d+$/.test(column.meta.name) && column.meta.role === null) {\n notes.add(POSITION_ISSUE.OTHER_VIEWS, { sample: column.meta.name });\n }\n }\n}\n\n/**\n * Note plain numeric `x` and `y` node columns a format does not read as positions.\n * @param snapshot - the graph\n * @param notes - receives the note\n */\nfunction noteUnread(snapshot: GraphSnapshot, notes: NoteCollector<PositionNoteCode>): void {\n const numeric = (name: string): Column | undefined =>\n [...snapshot.nodes].find(\n (c) => c.meta.name.toLowerCase() === name && c.meta.components === 1 && isNumeric(c.dtype),\n );\n const x = numeric(\"x\");\n const y = numeric(\"y\");\n if (x !== undefined && y !== undefined) {\n notes.add(POSITION_ISSUE.NOT_READ, { sample: x.meta.name });\n notes.add(POSITION_ISSUE.NOT_READ, { sample: y.meta.name });\n }\n}\n\n/**\n * Whether a dtype holds numbers.\n * @param dtype - the dtype\n * @returns true for the numeric dtypes\n */\nfunction isNumeric(dtype: string): boolean {\n return dtype === \"f64\" || dtype === \"f32\" || dtype === \"i32\" || dtype === \"u32\" || dtype === \"u8\";\n}\n\n/**\n * The notes with graph-io's English.\n * @param notes - the collector\n * @returns the notes\n */\nfunction noteList(notes: NoteCollector<PositionNoteCode>): PositionNote[] {\n return notes.list().map((n) => ({\n code: n.code,\n params: { count: n.count, samples: n.samples },\n elements: n.elements,\n message: `${PHRASES[n.code]} (${n.count})`,\n }));\n}\n\n/**\n * The answer for a file with no readable positions but position-like columns.\n * @param importer - the importer\n * @param snapshot - the graph\n * @param notes - the notes\n * @returns positions with nothing placed\n */\nfunction emptyPositions(\n importer: GraphImporter,\n snapshot: GraphSnapshot,\n notes: NoteCollector<PositionNoteCode>,\n): FilePositions {\n return {\n version: 1,\n source: { format: importer.format, tool: toolOf(snapshot.meta.creator), yAxis: \"up\" },\n units: \"file\",\n medianNodeSize: null,\n dims: 2,\n coords: new Float64Array(3 * snapshot.nodeCount).fill(Number.NaN),\n placed: 0,\n total: snapshot.nodeCount,\n usable: false,\n bounds: null,\n groups: [],\n notes: noteList(notes),\n };\n}\n\n// ------------------------------------------------------------ sizes and bounds\n\n/**\n * The median node diameter from the size columns the spelling names.\n * @param size - the size reader\n * @param n - the node count\n * @param containers - group containers, left out\n * @returns the median of each node's mean of width and height, or null when no node has a size\n */\nfunction medianSize(size: SizeReader, n: number, containers: ReadonlySet<number>): number | null {\n const sizes: number[] = [];\n for (let row = 0; row < n; row++) {\n const s = containers.has(row) ? null : size(row);\n if (s !== null) {\n sizes.push((s[0] + s[1]) / 2);\n }\n }\n return median(sizes);\n}\n\n/**\n * The box around every placed row.\n * @param values - the coordinates\n * @returns min and max, or null when none is placed\n */\nfunction boundsOf(values: Float64Array): FilePositions[\"bounds\"] {\n const min: Point = [Infinity, Infinity, Infinity];\n const max: Point = [-Infinity, -Infinity, -Infinity];\n for (let i = 0; i < values.length; i += 3) {\n if (Number.isNaN(values[i])) {\n continue;\n }\n for (let k = 0; k < 3; k++) {\n min[k] = Math.min(min[k], values[i + k]);\n max[k] = Math.max(max[k], values[i + k]);\n }\n }\n return min[0] === Infinity ? null : { min, max };\n}\n"],"names":["a","w"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"positions.js","sources":["../src/positions/codes.ts","../src/common/notes.ts","../src/positions/extract.ts"],"sourcesContent":["/**\n * The note codes of `extractPositions()`. Singular `W_POSITION_*` codes are about some nodes,\n * plural `W_POSITIONS_*` codes about the file as a whole. Keys drop the `W_` and `POSITION_` /\n * `POSITIONS_` prefixes.\n */\n\n/**\n * Every code a `PositionNote` carries.\n * @category Positions\n */\nexport const POSITION_ISSUE = Object.freeze({\n /** Every placed node sits on one point; the coordinates are dropped and `usable` is false. */\n STACKED: \"W_POSITION_STACKED\",\n /** Some nodes have no position. */\n PARTIAL: \"W_POSITION_PARTIAL\",\n /** Some coordinates are not finite numbers; those nodes count as unplaced. */\n NON_FINITE: \"W_POSITION_NON_FINITE\",\n /** The file mixes 2- and 3-coordinate positions. */\n DIMS_MIXED: \"W_POSITION_DIMS_MIXED\",\n /** A top-left coordinate has no width or height, so it was not moved to the center. */\n ANCHOR_NO_SIZE: \"W_POSITION_ANCHOR_NO_SIZE\",\n /** The file holds more than one view (layout); only the first is used. */\n OTHER_VIEWS: \"W_POSITION_OTHER_VIEWS\",\n /** The file has position-like columns this format does not read (plain `x` / `y`). */\n NOT_READ: \"W_POSITIONS_NOT_READ\",\n} as const);\n\n/**\n * A code of `POSITION_ISSUE`.\n * @category Positions\n */\nexport type PositionNoteCode = (typeof POSITION_ISSUE)[keyof typeof POSITION_ISSUE];\n","/**\n * The note collector file positions use (and file styles, after their rebase): one note per code\n * (and optional property), never one per element, with at most 8 distinct samples of 80\n * characters, a total count and the element indexes the note covers.\n */\n\n/** At most this many samples per note. */\nconst MAX_SAMPLES = 8;\n/** A sample is cut to this many characters. */\nconst MAX_SAMPLE_LENGTH = 80;\n\n/** One occurrence (or `count` occurrences) of a condition. */\ninterface NoteReport {\n /** An example of the offending value. */\n readonly sample?: unknown;\n /** The element the report is about, by index. */\n readonly element?: number;\n /** How many occurrences the report stands for; defaults to 1. */\n readonly count?: number;\n}\n\n/** A collected note, before a module shapes it into its own note type. */\ninterface CollectedNote<C extends string> {\n readonly code: C;\n readonly property: string | null;\n readonly count: number;\n readonly samples: readonly string[];\n readonly elements: readonly number[] | { readonly count: number };\n}\n\ninterface Collecting<C extends string> {\n readonly code: C;\n readonly property: string | null;\n count: number;\n readonly samples: string[];\n readonly elements: Set<number>;\n unindexed: boolean;\n}\n\n/** Collects notes, aggregated per (code, property), in the order their conditions first occur. */\nexport class NoteCollector<C extends string> {\n readonly #notes = new Map<string, Collecting<C>>();\n\n /**\n * Record a condition.\n * @param code - the condition\n * @param report - a sample, the element index and a count\n * @param property - what the note is about, or null\n */\n add(code: C, report: NoteReport = {}, property: string | null = null): void {\n const key = `${code}\\u0000${property ?? \"\"}`;\n let note = this.#notes.get(key);\n if (note === undefined) {\n note = { code, property, count: 0, samples: [], elements: new Set(), unindexed: false };\n this.#notes.set(key, note);\n }\n note.count += report.count ?? 1;\n if (report.element === undefined) {\n note.unindexed = true;\n } else {\n note.elements.add(report.element);\n }\n if (report.sample !== undefined && note.samples.length < MAX_SAMPLES) {\n const sample = sampleText(report.sample);\n if (!note.samples.includes(sample)) {\n note.samples.push(sample);\n }\n }\n }\n\n /**\n * The collected notes.\n * @returns one note per (code, property)\n */\n list(): CollectedNote<C>[] {\n return Array.from(this.#notes.values(), (n) => ({\n code: n.code,\n property: n.property,\n count: n.count,\n samples: [...n.samples],\n elements: n.unindexed ? { count: n.count } : Array.from(n.elements).sort((a, b) => a - b),\n }));\n }\n}\n\n/**\n * A sample as at most 80 characters of text.\n * @param value - the sample\n * @returns the text\n */\nfunction sampleText(value: unknown): string {\n const text = typeof value === \"string\" ? value : (JSON.stringify(value) ?? String(value));\n return text.length > MAX_SAMPLE_LENGTH ? `${text.slice(0, MAX_SAMPLE_LENGTH - 3)}...` : text;\n}\n","/**\n * `extractPositions()`: any format's stored node coordinates in the neutral convention (center,\n * y up, the file's unit, 3 components). The snapshot's role-`position` column keeps the values the\n * file wrote; this reads them through the spelling the column's `meta.extra` (or the importer's\n * `positions()` hook) declares.\n */\n\nimport type { Column, GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { NoteCollector } from \"../common/notes.js\";\nimport { type GraphTool, toolOf } from \"../common/units.js\";\nimport type { GraphImporter, ImportReport } from \"../types.js\";\nimport { POSITION_ISSUE, type PositionNoteCode } from \"./codes.js\";\nimport { median, toNeutral } from \"./convert.js\";\nimport type {\n ExtractPositionsOptions,\n FilePositionGroup,\n FilePositions,\n ImporterGroupBox,\n ImporterPositions,\n PositionColumnExtra,\n PositionNote,\n} from \"./types.js\";\n\ntype Point = [number, number, number];\n\n/** Reads one row's raw coordinates into `out`; false when the row has none. */\ntype RowReader = (row: number, out: Point) => boolean;\n\n/** Reads one row's width and height; null when the row has no size. */\ntype SizeReader = (row: number) => readonly [number, number] | null;\n\n/** Where a file's coordinates are and how they are spelled. */\ninterface Spelling {\n readonly read: RowReader;\n /** Reads a row's width and height from the size columns the spelling names; null without both. */\n readonly size: SizeReader;\n readonly extra: PositionColumnExtra;\n readonly groups: readonly ImporterGroupBox[];\n readonly medianNodeSize: number | null | undefined;\n readonly tool: GraphTool | null | undefined;\n}\n\n/** Report codes of format readers that mean the file mixes 2- and 3-coordinate positions. */\nconst DIMS_MIXED_CODES: ReadonlySet<string> = new Set([\"W_PAJEK_COORD_DIMS\", \"W_DOT_POS_DIMS\"]);\n\n/** graph-io's English for each note, for its own logs only. */\nconst PHRASES: Readonly<Record<PositionNoteCode, string>> = {\n W_POSITION_STACKED: \"every placed node is on one point; the positions were dropped\",\n W_POSITION_PARTIAL: \"nodes have no position\",\n W_POSITION_NON_FINITE: \"positions are not finite numbers\",\n W_POSITION_DIMS_MIXED: \"positions mix 2 and 3 coordinates\",\n W_POSITION_ANCHOR_NO_SIZE: \"top-left positions have no size and were not moved to the center\",\n W_POSITION_OTHER_VIEWS: \"other views were not used\",\n W_POSITIONS_NOT_READ: \"position-like columns this format does not read\",\n};\n\n/**\n * A file's stored node coordinates in the neutral convention: each node's center, y up, in the\n * file's own unit. Call it with the importer that read the snapshot and the report it returned.\n * @example\n * ```ts\n * const { snapshot, report } = await importGraph(text, { format: \"gml\" });\n * const positions = extractPositions(gmlImporter, snapshot, report);\n * if (positions?.usable) console.log(positions.coords.subarray(0, 3)); // node 0's x, y, z\n * ```\n * @param importer - the importer that read the snapshot (its `positions()` hook, when it has one, says how the coordinates are spelled)\n * @param snapshot - the imported graph\n * @param report - the import's report\n * @param options - `signal` to abort\n * @returns the positions, or null when the file stores none and has no position-like columns\n * @category Positions\n */\nexport function extractPositions(\n importer: GraphImporter,\n snapshot: GraphSnapshot,\n report: ImportReport,\n options: ExtractPositionsOptions = {},\n): FilePositions | null {\n const signal = options.signal ?? null;\n signal?.throwIfAborted();\n const notes = new NoteCollector<PositionNoteCode>();\n const spelling = spellingOf(importer, snapshot, signal);\n if (spelling === null) {\n noteUnread(snapshot, notes);\n return notes.list().length === 0 ? null : emptyPositions(importer, snapshot, notes);\n }\n const n = snapshot.nodeCount;\n const coords = readRows(n, spelling, notes);\n signal?.throwIfAborted();\n const containers = containersOf(snapshot);\n if (spelling.extra.containersFollowChildren === true) {\n for (const row of containers) {\n coords.values.fill(Number.NaN, 3 * row, 3 * row + 3);\n }\n }\n const groups = applyGroups(spelling, coords);\n collectGroups(spelling, coords, containers, groups);\n const { placed, total } = countPlaced(coords, containers, notes);\n const stacked = dropStacked(coords, placed, notes);\n noteReport(report, notes);\n noteOtherViews(snapshot, notes);\n return {\n version: 1,\n source: {\n format: importer.format,\n tool: spelling.tool ?? toolOf(snapshot.meta.creator),\n yAxis: spelling.extra.yAxis ?? \"up\",\n },\n units: spelling.extra.units ?? \"file\",\n ...(spelling.extra.pxPerUnit === undefined ? {} : { pxPerUnit: spelling.extra.pxPerUnit }),\n ...(spelling.extra.viewerFit === undefined ? {} : { viewerFit: spelling.extra.viewerFit }),\n medianNodeSize: spelling.medianNodeSize ?? medianSize(spelling.size, n, containers),\n dims: coords.realZ ? 3 : 2,\n coords: coords.values,\n placed: stacked ? 0 : placed,\n total,\n usable: !stacked && placed > 0,\n bounds: stacked ? null : boundsOf(coords.values),\n groups,\n notes: noteList(notes),\n };\n}\n\n// ------------------------------------------------------------ spelling\n\n/**\n * Where the coordinates are: the importer's hook wins over the column's `meta.extra`.\n * @param importer - the importer\n * @param snapshot - the graph\n * @param signal - the abort signal\n * @returns the spelling, or null when the file stores no coordinates\n */\nfunction spellingOf(importer: GraphImporter, snapshot: GraphSnapshot, signal: AbortSignal | null): Spelling | null {\n const hook = importer.positions?.(snapshot, { signal }) ?? null;\n if (hook?.x !== undefined && hook.y !== undefined) {\n return plainSpelling(snapshot, hook);\n }\n const column = hook?.column === undefined ? snapshot.nodes.byRole(\"position\") : snapshot.nodes.get(hook.column);\n if (column === null || column.meta.components < 2) {\n return hook?.unplacedCircle === undefined ? null : circleSpelling(snapshot, hook);\n }\n const extra = { ...extraOf(column.meta.extra), ...extraOf(hook ?? {}) };\n return { read: vectorReader(column), size: sizeReader(snapshot, extra), extra, ...hookFields(hook) };\n}\n\n/**\n * The spelling of a file that places no node, whose program puts them round a circle (`unplacedCircle`).\n * @param snapshot - the graph\n * @param hook - the hook's answer, with its circle\n * @returns the spelling\n */\nfunction circleSpelling(snapshot: GraphSnapshot, hook: ImporterPositions): Spelling {\n const circle = hook.unplacedCircle;\n const n = snapshot.nodeCount;\n const read: RowReader = (row, out) => {\n if (circle === undefined || n === 0) {\n return false;\n }\n const a = ((circle.startDegrees + (circle.direction * 360 * row) / n) * Math.PI) / 180;\n out[0] = circle.center[0] + circle.radius * Math.cos(a);\n out[1] = circle.center[1] + circle.radius * Math.sin(a);\n out[2] = 0;\n return true;\n };\n const extra = { ...extraOf(hook), sourceDims: 2 } as const;\n return { read, size: sizeReader(snapshot, extra), extra, ...hookFields(hook) };\n}\n\n/**\n * The spelling of the simple hook form: plain x / y (/ z) columns.\n * @param snapshot - the graph\n * @param hook - the hook's answer\n * @returns the spelling, or null when a named column is missing\n */\nfunction plainSpelling(snapshot: GraphSnapshot, hook: ImporterPositions): Spelling | null {\n const x = snapshot.nodes.get(hook.x ?? \"\");\n const y = snapshot.nodes.get(hook.y ?? \"\");\n const z = hook.z === undefined ? null : snapshot.nodes.get(hook.z);\n if (x === null || y === null) {\n return null;\n }\n const read: RowReader = (row, out) => {\n if (!x.isSet(row) || !y.isSet(row)) {\n return false;\n }\n out[0] = Number(x.value(row));\n out[1] = Number(y.value(row));\n out[2] = z?.isSet(row) === true ? Number(z.value(row)) : 0;\n return true;\n };\n const extra = { ...extraOf(hook), sourceDims: z === null ? 2 : 3 } as const;\n return { read, size: sizeReader(snapshot, extra), extra, ...hookFields(hook) };\n}\n\n/**\n * The hook's fields beside the spelling.\n * @param hook - the hook's answer, or null\n * @returns groups, median node size and tool\n */\nfunction hookFields(hook: ImporterPositions | null): Pick<Spelling, \"groups\" | \"medianNodeSize\" | \"tool\"> {\n return { groups: hook?.groups ?? [], medianNodeSize: hook?.medianNodeSize, tool: hook?.tool };\n}\n\n/**\n * A reader over a 2- or 3-component column.\n * @param column - the column\n * @returns the reader\n */\nfunction vectorReader(column: Column): RowReader {\n return (row, out) => {\n if (!column.isSet(row)) {\n return false;\n }\n const v = column.value(row) as ArrayLike<number>;\n out[0] = v[0];\n out[1] = v[1];\n out[2] = v.length > 2 ? v[2] : 0;\n return true;\n };\n}\n\n/**\n * The spelling fields of an extra (or a hook's answer), each kept only when well formed.\n * @param source - a column's meta.extra or a hook's answer\n * @returns the fields\n */\nfunction extraOf(source: object): PositionColumnExtra {\n const extra = source as Readonly<Record<string, unknown>>;\n const out: Record<string, unknown> = {};\n const pick = (key: keyof PositionColumnExtra, ok: (v: unknown) => boolean): void => {\n if (ok(extra[key])) {\n out[key] = extra[key];\n }\n };\n pick(\"units\", (v) => v === \"px\" || v === \"file\");\n pick(\"sourceDims\", (v) => v === 2 || v === 3);\n pick(\"yAxis\", (v) => v === \"up\" || v === \"down\");\n pick(\"anchor\", (v) => v === \"center\" || v === \"top-left\");\n pick(\"width\", (v) => typeof v === \"string\");\n pick(\"height\", (v) => typeof v === \"string\");\n pick(\"pxPerUnit\", (v) => typeof v === \"number\" && Number.isFinite(v) && v > 0);\n pick(\"pxPerUnitY\", (v) => typeof v === \"number\" && Number.isFinite(v) && v > 0);\n pick(\"zOrigin\", (v) => typeof v === \"number\" && Number.isFinite(v));\n pick(\"zeroUnplaced\", (v) => typeof v === \"boolean\");\n pick(\"originUnplaced\", (v) => typeof v === \"boolean\");\n pick(\"containersFollowChildren\", (v) => typeof v === \"boolean\");\n const fit = extra.viewerFit as Readonly<Record<string, unknown>> | null | undefined;\n if (typeof fit?.padding === \"number\" && Number.isFinite(fit.padding) && fit.padding >= 0) {\n out.viewerFit = { padding: fit.padding };\n }\n return out;\n}\n\n// ------------------------------------------------------------ rows\n\n/** Coordinates by node index, with whether the file has a z that differs between nodes. */\ninterface Rows {\n readonly values: Float64Array;\n readonly realZ: boolean;\n}\n\n/**\n * Read every row and convert it to the neutral convention.\n * @param n - the node count\n * @param spelling - how the coordinates are spelled\n * @param notes - receives non-finite and anchor notes\n * @returns the coordinates (NaN rows have none)\n */\nfunction readRows(n: number, spelling: Spelling, notes: NoteCollector<PositionNoteCode>): Rows {\n const values = new Float64Array(3 * n).fill(Number.NaN);\n const p: Point = [0, 0, 0];\n for (let row = 0; row < n; row++) {\n if (!spelling.read(row, p)) {\n continue;\n }\n if (Number.isFinite(p[0]) && Number.isFinite(p[1]) && Number.isFinite(p[2])) {\n values.set(p, 3 * row);\n } else {\n notes.add(POSITION_ISSUE.NON_FINITE, { element: row, sample: p.join(\",\") });\n }\n }\n if (spelling.extra.zeroUnplaced === true) {\n dropZeroPile(values);\n }\n if (spelling.extra.originUnplaced === true) {\n placeUnplacedAtOrigin(values);\n }\n const realZ = spelling.extra.sourceDims === 3 && !constantZ(values);\n convertRows(values, spelling.extra, spelling.size, realZ, notes);\n return { values, realZ };\n}\n\n/**\n * Put every unplaced row at the origin, when at least one row is placed.\n * @param values - the coordinates, three per row; NaN rows are unplaced\n */\nfunction placeUnplacedAtOrigin(values: Float64Array): void {\n if (!values.some((v) => !Number.isNaN(v))) {\n return;\n }\n for (let i = 0; i < values.length; i += 3) {\n if (Number.isNaN(values[i])) {\n values.fill(0, i, i + 3);\n }\n }\n}\n\n/**\n * Convert every placed row in place.\n * @param values - the raw coordinates\n * @param extra - the spelling\n * @param size - reads a row's width and height\n * @param realZ - whether z differs between nodes\n * @param notes - receives the anchor note\n */\nfunction convertRows(\n values: Float64Array,\n extra: PositionColumnExtra,\n size: SizeReader,\n realZ: boolean,\n notes: NoteCollector<PositionNoteCode>,\n): void {\n const p: Point = [0, 0, 0];\n for (let i = 0; i < values.length; i += 3) {\n if (Number.isNaN(values[i])) {\n continue;\n }\n const s = extra.anchor === \"top-left\" ? size(i / 3) : null;\n if (extra.anchor === \"top-left\" && s === null) {\n notes.add(POSITION_ISSUE.ANCHOR_NO_SIZE, { element: i / 3 });\n }\n p[0] = values[i];\n p[1] = values[i + 1];\n p[2] = values[i + 2];\n toNeutral(p, extra, s, realZ);\n values.set(p, i);\n }\n}\n\n/**\n * Reads a row's width and height from the size columns a spelling names.\n * @param snapshot - the graph\n * @param extra - the spelling\n * @returns the reader; it answers null for a row without both, or when the columns are missing\n */\nfunction sizeReader(snapshot: GraphSnapshot, extra: PositionColumnExtra): SizeReader {\n const w = extra.width === undefined ? null : snapshot.nodes.get(extra.width);\n const h = extra.height === undefined ? null : snapshot.nodes.get(extra.height);\n if (w === null || h === null) {\n return () => null;\n }\n return (row) => {\n if (!w.isSet(row) || !h.isSet(row)) {\n return null;\n }\n const size: [number, number] = [Number(w.value(row)), Number(h.value(row))];\n return Number.isFinite(size[0]) && Number.isFinite(size[1]) ? size : null;\n };\n}\n\n/**\n * NetworkX writes (0, 0) for a node with no position: when other rows are placed, an exact (0, 0)\n * shared by two or more rows counts as unplaced.\n * @param values - the raw coordinates, changed in place\n */\nfunction dropZeroPile(values: Float64Array): void {\n const zeros: number[] = [];\n let others = 0;\n for (let i = 0; i < values.length; i += 3) {\n if (values[i] === 0 && values[i + 1] === 0) {\n zeros.push(i);\n } else if (!Number.isNaN(values[i])) {\n others++;\n }\n }\n if (zeros.length >= 2 && others > 0) {\n for (const i of zeros) {\n values.fill(Number.NaN, i, i + 3);\n }\n }\n}\n\n/**\n * Whether every placed row has the same z (Pajek writes z = 0.5 on 2D drawings).\n * @param values - the raw coordinates\n * @returns true when z never differs\n */\nfunction constantZ(values: Float64Array): boolean {\n let z = Number.NaN;\n for (let i = 0; i < values.length; i += 3) {\n if (Number.isNaN(values[i])) {\n continue;\n }\n if (Number.isNaN(z)) {\n z = values[i + 2];\n } else if (values[i + 2] !== z) {\n return false;\n }\n }\n return true;\n}\n\n// ------------------------------------------------------------ groups\n\n/**\n * The nodes another node names as its parent: group containers.\n * @param snapshot - the graph\n * @returns the container indexes\n */\nfunction containersOf(snapshot: GraphSnapshot): Set<number> {\n const out = new Set<number>();\n const parent = snapshot.nodes.byRole(\"parent\");\n if (parent === null) {\n return out;\n }\n for (let row = 0; row < parent.length; row++) {\n const v = parent.isSet(row) ? parent.value(row) : undefined;\n if (typeof v === \"number\") {\n out.add(v);\n }\n }\n return out;\n}\n\n/**\n * The hook's group boxes in the neutral convention; a container with no coordinate of its own is\n * placed at its box's center.\n * @param spelling - the spelling and the hook's boxes\n * @param rows - the coordinates, changed in place\n * @returns the boxes\n */\nfunction applyGroups(spelling: Spelling, rows: Rows): FilePositionGroup[] {\n const out: FilePositionGroup[] = [];\n for (const { node, box } of spelling.groups) {\n const p: Point = [box.x, box.y, 0];\n toNeutral(p, spelling.extra, [box.width, box.height], false);\n if (Number.isNaN(rows.values[3 * node])) {\n rows.values.set(p, 3 * node);\n }\n if (!out.some((g) => g.node === node)) {\n out.push({ node, box: { x: p[0], y: p[1], width: box.width, height: box.height } });\n }\n }\n return out;\n}\n\n/**\n * Boxes for the containers the file gives a coordinate and a size (yEd groups).\n * @param spelling - the size reader\n * @param rows - the coordinates\n * @param containers - the container indexes\n * @param groups - receives the boxes\n */\nfunction collectGroups(\n spelling: Spelling,\n rows: Rows,\n containers: ReadonlySet<number>,\n groups: FilePositionGroup[],\n): void {\n for (const node of containers) {\n const size = spelling.size(node);\n const i = 3 * node;\n if (size !== null && !Number.isNaN(rows.values[i]) && !groups.some((g) => g.node === node)) {\n groups.push({ node, box: { x: rows.values[i], y: rows.values[i + 1], width: size[0], height: size[1] } });\n }\n }\n}\n\n// ------------------------------------------------------------ counts and notes\n\n/**\n * Count the placed rows and the rows that need a position; note the unplaced ones.\n * @param rows - the coordinates\n * @param containers - containers without a coordinate do not need one\n * @param notes - receives the partial note\n * @returns placed and total\n */\nfunction countPlaced(\n rows: Rows,\n containers: ReadonlySet<number>,\n notes: NoteCollector<PositionNoteCode>,\n): { placed: number; total: number } {\n const { values } = rows;\n const unplaced: number[] = [];\n let placed = 0;\n let total = 0;\n for (let row = 0; 3 * row < values.length; row++) {\n const has = !Number.isNaN(values[3 * row]);\n if (has) {\n placed++;\n } else if (!containers.has(row)) {\n unplaced.push(row);\n }\n total += has || !containers.has(row) ? 1 : 0;\n }\n if (placed > 0 && unplaced.length > 0) {\n for (const element of unplaced) {\n notes.add(POSITION_ISSUE.PARTIAL, { element });\n }\n }\n return { placed, total };\n}\n\n/**\n * Drop the coordinates when every placed node sits on one point.\n * @param rows - the coordinates, cleared in place when stacked\n * @param placed - the placed count\n * @param notes - receives the stacked note\n * @returns whether they were stacked\n */\nfunction dropStacked(rows: Rows, placed: number, notes: NoteCollector<PositionNoteCode>): boolean {\n if (placed < 2) {\n return false;\n }\n const { values } = rows;\n let first = -1;\n for (let i = 0; i < values.length; i += 3) {\n if (Number.isNaN(values[i])) {\n continue;\n }\n if (first < 0) {\n first = i;\n } else if (\n values[i] !== values[first] ||\n values[i + 1] !== values[first + 1] ||\n values[i + 2] !== values[first + 2]\n ) {\n return false;\n }\n }\n notes.add(POSITION_ISSUE.STACKED, {\n count: placed,\n sample: Array.from(values.subarray(first, first + 3)).join(\",\"),\n });\n values.fill(Number.NaN);\n return true;\n}\n\n/**\n * Lift the format readers' mixed-dimension warnings into the shared code.\n * @param report - the import report\n * @param notes - receives the note\n */\nfunction noteReport(report: ImportReport, notes: NoteCollector<PositionNoteCode>): void {\n for (const issue of report.issues) {\n if (DIMS_MIXED_CODES.has(issue.code)) {\n notes.add(POSITION_ISSUE.DIMS_MIXED, { sample: issue.code });\n }\n }\n}\n\n/**\n * Note the extra view columns of a CX file (`position@2`, ...): only the first view is used.\n * @param snapshot - the graph\n * @param notes - receives the note\n */\nfunction noteOtherViews(snapshot: GraphSnapshot, notes: NoteCollector<PositionNoteCode>): void {\n for (const column of snapshot.nodes) {\n if (/^position@\\d+$/.test(column.meta.name) && column.meta.role === null) {\n notes.add(POSITION_ISSUE.OTHER_VIEWS, { sample: column.meta.name });\n }\n }\n}\n\n/**\n * Note plain numeric `x` and `y` node columns a format does not read as positions.\n * @param snapshot - the graph\n * @param notes - receives the note\n */\nfunction noteUnread(snapshot: GraphSnapshot, notes: NoteCollector<PositionNoteCode>): void {\n const numeric = (name: string): Column | undefined =>\n [...snapshot.nodes].find(\n (c) => c.meta.name.toLowerCase() === name && c.meta.components === 1 && isNumeric(c.dtype),\n );\n const x = numeric(\"x\");\n const y = numeric(\"y\");\n if (x !== undefined && y !== undefined) {\n notes.add(POSITION_ISSUE.NOT_READ, { sample: x.meta.name });\n notes.add(POSITION_ISSUE.NOT_READ, { sample: y.meta.name });\n }\n}\n\n/**\n * Whether a dtype holds numbers.\n * @param dtype - the dtype\n * @returns true for the numeric dtypes\n */\nfunction isNumeric(dtype: string): boolean {\n return dtype === \"f64\" || dtype === \"f32\" || dtype === \"i32\" || dtype === \"u32\" || dtype === \"u8\";\n}\n\n/**\n * The notes with graph-io's English.\n * @param notes - the collector\n * @returns the notes\n */\nfunction noteList(notes: NoteCollector<PositionNoteCode>): PositionNote[] {\n return notes.list().map((n) => ({\n code: n.code,\n params: { count: n.count, samples: n.samples },\n elements: n.elements,\n message: `${PHRASES[n.code]} (${n.count})`,\n }));\n}\n\n/**\n * The answer for a file with no readable positions but position-like columns.\n * @param importer - the importer\n * @param snapshot - the graph\n * @param notes - the notes\n * @returns positions with nothing placed\n */\nfunction emptyPositions(\n importer: GraphImporter,\n snapshot: GraphSnapshot,\n notes: NoteCollector<PositionNoteCode>,\n): FilePositions {\n return {\n version: 1,\n source: { format: importer.format, tool: toolOf(snapshot.meta.creator), yAxis: \"up\" },\n units: \"file\",\n medianNodeSize: null,\n dims: 2,\n coords: new Float64Array(3 * snapshot.nodeCount).fill(Number.NaN),\n placed: 0,\n total: snapshot.nodeCount,\n usable: false,\n bounds: null,\n groups: [],\n notes: noteList(notes),\n };\n}\n\n// ------------------------------------------------------------ sizes and bounds\n\n/**\n * The median node diameter from the size columns the spelling names.\n * @param size - the size reader\n * @param n - the node count\n * @param containers - group containers, left out\n * @returns the median of each node's mean of width and height, or null when no node has a size\n */\nfunction medianSize(size: SizeReader, n: number, containers: ReadonlySet<number>): number | null {\n const sizes: number[] = [];\n for (let row = 0; row < n; row++) {\n const s = containers.has(row) ? null : size(row);\n if (s !== null) {\n sizes.push((s[0] + s[1]) / 2);\n }\n }\n return median(sizes);\n}\n\n/**\n * The box around every placed row.\n * @param values - the coordinates\n * @returns min and max, or null when none is placed\n */\nfunction boundsOf(values: Float64Array): FilePositions[\"bounds\"] {\n const min: Point = [Infinity, Infinity, Infinity];\n const max: Point = [-Infinity, -Infinity, -Infinity];\n for (let i = 0; i < values.length; i += 3) {\n if (Number.isNaN(values[i])) {\n continue;\n }\n for (let k = 0; k < 3; k++) {\n min[k] = Math.min(min[k], values[i + k]);\n max[k] = Math.max(max[k], values[i + k]);\n }\n }\n return min[0] === Infinity ? null : { min, max };\n}\n"],"names":["a","w"],"mappings":"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"}
|
package/dist/sources-cypher.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { b as throwIfAborted } from "./chunks/input-
|
|
2
|
-
import { P as PRECISION_CODE, ah as ImportError } from "./chunks/report-
|
|
3
|
-
import { C as CYPHER_DESCRIPTOR, N as NEO4J_DESCRIPTOR, a as NEPTUNE_DESCRIPTOR, S as SOURCE_ISSUE } from "./chunks/codes-
|
|
4
|
-
import { w as warnOn, f as failOn,
|
|
5
|
-
import { sha256Hex } from "./chunks/sigv4-
|
|
1
|
+
import { b as throwIfAborted } from "./chunks/input-CAxt_aV-.js";
|
|
2
|
+
import { P as PRECISION_CODE, ah as ImportError } from "./chunks/report-CwMfYa9J.js";
|
|
3
|
+
import { C as CYPHER_DESCRIPTOR, N as NEO4J_DESCRIPTOR, a as NEPTUNE_DESCRIPTOR, S as SOURCE_ISSUE } from "./chunks/codes-BE2xir2k.js";
|
|
4
|
+
import { w as warnOn, f as failOn, q as SOURCE_DEGREE_ATTR, b as failAlone, o as originOf, u as unwrapCredential, d as defineSource, C as CYPHER_SOURCE_ID, h as NEO4J_SOURCE_ID, i as NEPTUNE_SOURCE_ID } from "./chunks/credentials-CmvJXYeH.js";
|
|
5
|
+
import { sha256Hex } from "./chunks/sigv4-BXwVbza3.js";
|
|
6
6
|
import { INVALID_INDEX } from "@graphty/graph-format";
|
|
7
|
-
import { t as transportOptions, i as isLoopback } from "./chunks/context-
|
|
7
|
+
import { t as transportOptions, i as isLoopback } from "./chunks/context-DizmppHy.js";
|
|
8
8
|
class GraphNode {
|
|
9
9
|
/**
|
|
10
10
|
* Create one.
|
|
@@ -544,6 +544,18 @@ function edgePage(profile, filters, pageSize, after) {
|
|
|
544
544
|
`ORDER BY key LIMIT ${pageSize}`
|
|
545
545
|
].filter((l) => l !== null).join(" ");
|
|
546
546
|
}
|
|
547
|
+
function edgesAmong(profile, filters) {
|
|
548
|
+
const ka = idExpression("a", profile, filters);
|
|
549
|
+
const kb = idExpression("b", profile, filters);
|
|
550
|
+
const ends = [nodePredicate("a", filters), nodePredicate("b", filters)].filter((p) => p !== null);
|
|
551
|
+
const rest = ends.length === 0 ? "" : ` AND ${ends.join(" AND ")}`;
|
|
552
|
+
const pattern = `MATCH (a)-[r${typesPattern(filters)}]->(b)`;
|
|
553
|
+
return [
|
|
554
|
+
`${pattern} WHERE ${ka} IN $keys AND ${kb} <= $last${rest} RETURN a, r, b`,
|
|
555
|
+
"UNION ALL",
|
|
556
|
+
`${pattern} WHERE ${kb} IN $keys AND ${ka} <= $last AND NOT ${ka} IN $keys${rest} RETURN a, r, b`
|
|
557
|
+
].join(" ");
|
|
558
|
+
}
|
|
547
559
|
function neighborhood(profile, filters, shape, degree) {
|
|
548
560
|
const rel = `[${typesPattern(filters)}*1..${shape.depth}]`;
|
|
549
561
|
const [left, right] = ARROWS[shape.direction];
|
|
@@ -576,6 +588,10 @@ function counts(filters) {
|
|
|
576
588
|
`MATCH (a)-[r${typesPattern(filters)}]->(b)${whereClause(where.length === 0 ? null : where.join(" AND "))} RETURN count(r) AS c`
|
|
577
589
|
];
|
|
578
590
|
}
|
|
591
|
+
function storeCount(label) {
|
|
592
|
+
const pattern = label === void 0 ? "n" : `n:${label}`;
|
|
593
|
+
return `MATCH (${pattern}) RETURN count(n) AS c`;
|
|
594
|
+
}
|
|
579
595
|
const MAX_SERVER_MESSAGE = 500;
|
|
580
596
|
function serverError(report, err, origin, database) {
|
|
581
597
|
const code = err.code ?? "";
|
|
@@ -922,6 +938,13 @@ function queryApiTransport(input) {
|
|
|
922
938
|
};
|
|
923
939
|
}
|
|
924
940
|
const DIRECTIONS = /* @__PURE__ */ new Set(["out", "in", "both"]);
|
|
941
|
+
function withoutTrailingSemicolons(query) {
|
|
942
|
+
let end = query.length;
|
|
943
|
+
while (end > 0 && query[end - 1] === ";") {
|
|
944
|
+
end--;
|
|
945
|
+
}
|
|
946
|
+
return query.slice(0, end);
|
|
947
|
+
}
|
|
925
948
|
function listParam(value, name, report) {
|
|
926
949
|
if (value === void 0 || value === null) {
|
|
927
950
|
return [];
|
|
@@ -1010,9 +1033,10 @@ class Reader {
|
|
|
1010
1033
|
/**
|
|
1011
1034
|
* The pages of a read, as `mode` asks.
|
|
1012
1035
|
* @param cursor - where to resume
|
|
1036
|
+
* @param counting - whether a first page of mode "all" may count what the source holds
|
|
1013
1037
|
* @yields one page at a time
|
|
1014
1038
|
*/
|
|
1015
|
-
async *pages(cursor) {
|
|
1039
|
+
async *pages(cursor, counting = true) {
|
|
1016
1040
|
const { params, ctx } = this;
|
|
1017
1041
|
const { report } = ctx;
|
|
1018
1042
|
const mode = params.mode ?? (typeof params.query === "string" && params.query !== "" ? "query" : "all");
|
|
@@ -1020,11 +1044,7 @@ class Reader {
|
|
|
1020
1044
|
if (typeof params.query !== "string" || params.query.trim() === "") {
|
|
1021
1045
|
failOn(report, "E_SOURCE_PARAM", "mode query needs a query", { name: "query", reason: "required" });
|
|
1022
1046
|
}
|
|
1023
|
-
|
|
1024
|
-
const collected = new Collector();
|
|
1025
|
-
collected.add(result, false);
|
|
1026
|
-
requireGraph(result, collected, report);
|
|
1027
|
-
yield { collected, next: null };
|
|
1047
|
+
yield await this.userQuery(params.query, cursor);
|
|
1028
1048
|
return;
|
|
1029
1049
|
}
|
|
1030
1050
|
const profile = await this.profile();
|
|
@@ -1042,21 +1062,71 @@ class Reader {
|
|
|
1042
1062
|
yield { collected, next: null };
|
|
1043
1063
|
return;
|
|
1044
1064
|
}
|
|
1045
|
-
yield* this.everything(profile, cursor);
|
|
1065
|
+
yield* this.everything(profile, cursor, counting);
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Mode "query": the reader's own query, as written. With a node cap (or a cursor from a capped
|
|
1069
|
+
* run) the server returns at most that many rows (`CALL { query } RETURN * LIMIT n`), and a full
|
|
1070
|
+
* result hands back a cursor that runs the query again with twice the rows, for the caller to
|
|
1071
|
+
* merge. A server that refuses the wrapper fails the load with `E_SOURCE_PARAM` (`name:
|
|
1072
|
+
* "maxNodes"`, `reason: "uncappable"`): the query is never run past the cap the caller set.
|
|
1073
|
+
* @param query - the query
|
|
1074
|
+
* @param cursor - where to resume: `{ rows }` from an earlier capped run
|
|
1075
|
+
* @returns the one page
|
|
1076
|
+
*/
|
|
1077
|
+
async userQuery(query, cursor) {
|
|
1078
|
+
const { params, ctx } = this;
|
|
1079
|
+
const parameters = params.parameters ?? {};
|
|
1080
|
+
const asked = cursor?.rows ?? ctx.limits.maxNodes;
|
|
1081
|
+
const rows = asked === void 0 || asked === null ? null : Number(checkedInteger(asked, "maxNodes", 1, Number.MAX_SAFE_INTEGER, ctx.report));
|
|
1082
|
+
let result;
|
|
1083
|
+
try {
|
|
1084
|
+
result = await this.transport.run(
|
|
1085
|
+
rows === null ? query : `CALL {
|
|
1086
|
+
${withoutTrailingSemicolons(query.trim())}
|
|
1087
|
+
}
|
|
1088
|
+
RETURN * LIMIT ${String(rows)}`,
|
|
1089
|
+
parameters
|
|
1090
|
+
);
|
|
1091
|
+
} catch (err) {
|
|
1092
|
+
if (rows === null || !(err instanceof ImportError) || err.issue?.code !== SOURCE_ISSUE.E_SOURCE_QUERY) {
|
|
1093
|
+
throw err;
|
|
1094
|
+
}
|
|
1095
|
+
return failOn(ctx.report, "E_SOURCE_PARAM", "the server cannot cap this query; load it without maxNodes", {
|
|
1096
|
+
name: "maxNodes",
|
|
1097
|
+
reason: "uncappable"
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1100
|
+
const collected = new Collector();
|
|
1101
|
+
collected.add(result, false);
|
|
1102
|
+
requireGraph(result, collected, ctx.report);
|
|
1103
|
+
const full = rows !== null && result.rows.length >= rows;
|
|
1104
|
+
return { collected, next: full ? { rows: rows * 2 } : null };
|
|
1046
1105
|
}
|
|
1047
1106
|
/**
|
|
1048
1107
|
* Mode "all": the nodes, then the relationships with their ends, each paged by keyset on the
|
|
1049
1108
|
* id expression (never SKIP), so a page is stable under unrelated writes.
|
|
1050
1109
|
* @param profile - the server's profile
|
|
1051
1110
|
* @param cursor - where to resume
|
|
1111
|
+
* @param counting - whether a first page may count what the source holds
|
|
1052
1112
|
* @yields one page at a time
|
|
1053
1113
|
*/
|
|
1054
|
-
async *everything(profile, cursor) {
|
|
1114
|
+
async *everything(profile, cursor, counting) {
|
|
1055
1115
|
const { params, ctx } = this;
|
|
1056
1116
|
const size = checkedInteger(params.pageSize ?? DEFAULT_PAGE_SIZE, "pageSize", 1, MAX_PAGE_SIZE, ctx.report);
|
|
1117
|
+
if (cursor === null && counting) {
|
|
1118
|
+
this.counted = await this.count(profile);
|
|
1119
|
+
}
|
|
1120
|
+
const cap = ctx.limits.maxNodes;
|
|
1121
|
+
if (cap !== void 0 && cursor?.phase !== "edges") {
|
|
1122
|
+
const capped = Number(checkedInteger(cap, "maxNodes", 1, Number.MAX_SAFE_INTEGER, ctx.report));
|
|
1123
|
+
yield* this.cappedNodes(profile, cursor, Math.min(Number(size), capped));
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1057
1126
|
let phase = cursor?.phase === "edges" ? "edges" : "nodes";
|
|
1058
1127
|
let after = cursor?.after ?? null;
|
|
1059
|
-
const
|
|
1128
|
+
const { counted } = this;
|
|
1129
|
+
const total = params.countFirst === true && counted !== void 0 ? (counted.nodes ?? 0) + (counted.edges ?? 0) : void 0;
|
|
1060
1130
|
for (; ; ) {
|
|
1061
1131
|
const nodes = phase === "nodes";
|
|
1062
1132
|
const { collected, rows, fields } = await this.generated(
|
|
@@ -1075,13 +1145,60 @@ class Reader {
|
|
|
1075
1145
|
}
|
|
1076
1146
|
}
|
|
1077
1147
|
/**
|
|
1078
|
-
*
|
|
1079
|
-
*
|
|
1148
|
+
* Mode "all" under a node cap: pages of at most the cap's nodes, each with the relationships
|
|
1149
|
+
* among the nodes loaded so far, so a capped load stops at its cap with its edges, and its
|
|
1150
|
+
* next page (`data.more`) continues by key.
|
|
1151
|
+
* @param profile - the server's profile
|
|
1152
|
+
* @param cursor - where to resume
|
|
1153
|
+
* @param size - the page size
|
|
1154
|
+
* @yields one page at a time
|
|
1155
|
+
*/
|
|
1156
|
+
async *cappedNodes(profile, cursor, size) {
|
|
1157
|
+
let after = cursor?.after ?? null;
|
|
1158
|
+
for (; ; ) {
|
|
1159
|
+
const { collected, rows, fields } = await this.generated(
|
|
1160
|
+
(d) => nodePage(profile, this.filters, String(size), after !== null, d),
|
|
1161
|
+
after === null ? {} : { after }
|
|
1162
|
+
);
|
|
1163
|
+
const at = fields.indexOf("key");
|
|
1164
|
+
const last = rows.at(-1)?.[at];
|
|
1165
|
+
const key = typeof last === "string" || typeof last === "number" ? last : null;
|
|
1166
|
+
if (key !== null) {
|
|
1167
|
+
const keys = rows.map((row) => row[at]);
|
|
1168
|
+
const among = await this.transport.run(edgesAmong(profile, this.filters), { keys, last: key });
|
|
1169
|
+
collected.add(among, false);
|
|
1170
|
+
}
|
|
1171
|
+
const next = rows.length >= size && key !== null ? { phase: "nodes", after: key } : null;
|
|
1172
|
+
yield { collected, next };
|
|
1173
|
+
if (next === null) {
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
after = key;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* What a first page of mode "all" counts: with `countFirst`, the nodes and relationships the
|
|
1181
|
+
* filters match (for progress too); else, on Neo4j with at most one label and the server's
|
|
1182
|
+
* ids, the nodes from the count store; else nothing.
|
|
1183
|
+
* @param profile - the server's profile
|
|
1184
|
+
* @returns the count, or undefined
|
|
1080
1185
|
*/
|
|
1081
|
-
async
|
|
1082
|
-
const
|
|
1083
|
-
|
|
1084
|
-
|
|
1186
|
+
async count(profile) {
|
|
1187
|
+
const first = async (statement) => {
|
|
1188
|
+
const c = Number((await this.transport.run(statement, {})).rows[0]?.[0]);
|
|
1189
|
+
return Number.isSafeInteger(c) && c >= 0 ? c : void 0;
|
|
1190
|
+
};
|
|
1191
|
+
const { labels, idProperty } = this.filters;
|
|
1192
|
+
if (this.params.countFirst === true) {
|
|
1193
|
+
const [n, r] = counts(this.filters);
|
|
1194
|
+
const [nodes2, edges] = await Promise.all([first(n), first(r)]);
|
|
1195
|
+
return { ...nodes2 === void 0 ? {} : { nodes: nodes2 }, ...edges === void 0 ? {} : { edges } };
|
|
1196
|
+
}
|
|
1197
|
+
if (profile.name !== "neo4j" || labels.length > 1 || idProperty !== null) {
|
|
1198
|
+
return void 0;
|
|
1199
|
+
}
|
|
1200
|
+
const nodes = await first(storeCount(labels[0]));
|
|
1201
|
+
return nodes === void 0 ? void 0 : { nodes };
|
|
1085
1202
|
}
|
|
1086
1203
|
/**
|
|
1087
1204
|
* The server facts and validators of what was read.
|
|
@@ -1154,7 +1271,8 @@ function cypher(preset) {
|
|
|
1154
1271
|
break;
|
|
1155
1272
|
}
|
|
1156
1273
|
}
|
|
1157
|
-
|
|
1274
|
+
const total = reader.counted === void 0 ? {} : { total: reader.counted };
|
|
1275
|
+
return ctx.finish({ next, ...total, ...await reader.facts(lines) });
|
|
1158
1276
|
}),
|
|
1159
1277
|
expand: (request, sink, ctx) => withReader(request.params, ctx, preset, (reader) => expand(reader, request, sink)),
|
|
1160
1278
|
probe: (params, ctx) => withReader(params, ctx, preset, async (reader) => {
|
|
@@ -1163,7 +1281,7 @@ function cypher(preset) {
|
|
|
1163
1281
|
}),
|
|
1164
1282
|
validate: (params, seen, ctx) => withReader(params, ctx, preset, async (reader) => {
|
|
1165
1283
|
const lines = [];
|
|
1166
|
-
for await (const page of reader.pages(null)) {
|
|
1284
|
+
for await (const page of reader.pages(null, false)) {
|
|
1167
1285
|
lines.push(...canonicalRows(page.collected, reader.idProperty));
|
|
1168
1286
|
}
|
|
1169
1287
|
const { validators } = await reader.facts(lines);
|