@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
|
@@ -36,11 +36,16 @@ import {
|
|
|
36
36
|
LABEL_ATTRIBUTE,
|
|
37
37
|
PARENT_COLUMN,
|
|
38
38
|
POS_ATTRIBUTE,
|
|
39
|
+
RANK_COLUMN,
|
|
40
|
+
RANK_SET_COLUMN,
|
|
39
41
|
SOURCE_PORT_COLUMN,
|
|
40
42
|
TARGET_PORT_COLUMN,
|
|
41
43
|
} from "./names.js";
|
|
42
44
|
import { DOT_ATTRIBUTE_CLASH_CODE, DOT_STYLE_CAPABILITIES, dotStyledExport, isHtmlString } from "./styles.js";
|
|
43
45
|
|
|
46
|
+
/** The node columns written as rank subgraphs rather than as node attributes. */
|
|
47
|
+
const RANK_COLUMNS: ReadonlySet<string> = new Set([RANK_COLUMN, RANK_SET_COLUMN]);
|
|
48
|
+
|
|
44
49
|
/** What the writer takes: the format's options, the common ones and the styles. */
|
|
45
50
|
type DotWriteOptions = DotExportOptions & CommonExportOptions & ExporterStyleOptions;
|
|
46
51
|
|
|
@@ -611,7 +616,7 @@ class ExportPlan {
|
|
|
611
616
|
*/
|
|
612
617
|
private writesNodeColumn(column: Column): boolean {
|
|
613
618
|
const { name, role } = column.meta;
|
|
614
|
-
if (!isTextualDtype(column) || name === CLUSTER_COLUMN) {
|
|
619
|
+
if (!isTextualDtype(column) || name === CLUSTER_COLUMN || RANK_COLUMNS.has(name)) {
|
|
615
620
|
return false;
|
|
616
621
|
}
|
|
617
622
|
if (role !== null && SKIPPED_NODE_ROLES.has(role)) {
|
|
@@ -875,10 +880,41 @@ class ExportPlan {
|
|
|
875
880
|
for (let i = 0; i < snapshot.nodeCount; i++) {
|
|
876
881
|
yield* this.writeNode(i, 1, emitted);
|
|
877
882
|
}
|
|
883
|
+
yield* this.writeRanks();
|
|
878
884
|
yield* this.writeEdges();
|
|
879
885
|
yield "}\n";
|
|
880
886
|
}
|
|
881
887
|
|
|
888
|
+
/**
|
|
889
|
+
* Write each rank subgraph the `graphty.rank` and `graphty.rankSet` columns hold, after the nodes: a named one
|
|
890
|
+
* under its name, an anonymous one (`%<n>`) as an anonymous subgraph.
|
|
891
|
+
* @yields the statements
|
|
892
|
+
* @returns nothing
|
|
893
|
+
*/
|
|
894
|
+
private *writeRanks(): Generator<string> {
|
|
895
|
+
const { nodes } = this.snapshot;
|
|
896
|
+
const rank = nodes.get(RANK_COLUMN);
|
|
897
|
+
const set = nodes.get(RANK_SET_COLUMN);
|
|
898
|
+
if (rank === null || set === null) {
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
const sets = new Map<string, { rank: string; members: string[] }>();
|
|
902
|
+
for (let i = 0; i < this.snapshot.nodeCount; i++) {
|
|
903
|
+
if (rank.isSet(i) && set.isSet(i)) {
|
|
904
|
+
const key = String(set.value(i));
|
|
905
|
+
const entry = sets.get(key) ?? { rank: String(rank.value(i)), members: [] };
|
|
906
|
+
entry.members.push(writeId(this.idText(i)));
|
|
907
|
+
sets.set(key, entry);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
// anonymous ones in their number's order, so the file read back numbers them the same
|
|
911
|
+
const order = (key: string): number => (key.startsWith("%") ? Number(key.slice(1)) : -1);
|
|
912
|
+
for (const [key, entry] of [...sets].sort(([a], [b]) => order(a) - order(b))) {
|
|
913
|
+
const head = key.startsWith("%") ? "" : `subgraph ${quoteDotId(key)} `;
|
|
914
|
+
yield `${this.indent}${head}{ rank=${quoteDotId(entry.rank)}; ${entry.members.join("; ")}; }\n`;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
882
918
|
/**
|
|
883
919
|
* Write one node (and, for a container, its cluster block with the members nested).
|
|
884
920
|
* @param i - the node index
|
|
@@ -98,6 +98,8 @@ import {
|
|
|
98
98
|
PIN_ATTRIBUTE,
|
|
99
99
|
POS_ATTRIBUTE,
|
|
100
100
|
POSITION_COLUMN,
|
|
101
|
+
RANK_COLUMN,
|
|
102
|
+
RANK_SET_COLUMN,
|
|
101
103
|
SOURCE_PORT_COLUMN,
|
|
102
104
|
TARGET_PORT_COLUMN,
|
|
103
105
|
} from "./names.js";
|
|
@@ -177,8 +179,13 @@ export const DOT_ISSUE = Object.freeze({
|
|
|
177
179
|
AMBIGUOUS_GRAPH_NAME: AMBIGUOUS_GRAPH_NAME_CODE,
|
|
178
180
|
/** A badly delimited numeral (`1e3`) split into two tokens, as Graphviz does with a warning. */
|
|
179
181
|
NUMERAL_AMBIGUITY: "W_DOT_NUMERAL_AMBIGUITY",
|
|
180
|
-
/**
|
|
182
|
+
/**
|
|
183
|
+
* Attributes of a subgraph that is not a cluster cannot be represented, except its `rank`, which is kept in the
|
|
184
|
+
* `graphty.rank` and `graphty.rankSet` node columns.
|
|
185
|
+
*/
|
|
181
186
|
SUBGRAPH_ATTRIBUTES_DROPPED: "W_DOT_SUBGRAPH_ATTRIBUTES_DROPPED",
|
|
187
|
+
/** A node in two rank subgraphs (`rank=same` and the like) keeps the first one's rank. */
|
|
188
|
+
RANK_CONFLICT: "W_DOT_RANK_CONFLICT",
|
|
182
189
|
/** A port on a node statement has no meaning and was dropped. */
|
|
183
190
|
NODE_PORT_DROPPED: "W_DOT_NODE_PORT_DROPPED",
|
|
184
191
|
/** A plain node and a cluster share a name and were merged into one container node. */
|
|
@@ -262,8 +269,35 @@ const EXTENSIONS: readonly string[] = Object.freeze([".dot", ".gv"]);
|
|
|
262
269
|
const MIME_TYPES: readonly string[] = Object.freeze(["text/vnd.graphviz"]);
|
|
263
270
|
const CLUSTER_PREFIX = "cluster";
|
|
264
271
|
const CLUSTER_ATTRIBUTE = "cluster";
|
|
272
|
+
/** The subgraph attribute that puts its nodes on one rank, or on the first or last. */
|
|
273
|
+
const RANK_ATTRIBUTE = "rank";
|
|
274
|
+
/** The values of `rank` Graphviz knows (lib/common/const.h: SAMERANK ... SINKRANK). */
|
|
275
|
+
const RANK_KINDS: ReadonlySet<string> = new Set(["same", "min", "max", "source", "sink"]);
|
|
265
276
|
const STATEMENTS_PER_ABORT_CHECK = 64;
|
|
266
277
|
const MAX_ANCESTOR_WALK = 4096;
|
|
278
|
+
/**
|
|
279
|
+
* The graph attributes a cluster takes from the graphs around it when it sets none of its own: Graphviz gives a
|
|
280
|
+
* subgraph every graph attribute its enclosing graphs set before it opened (a root `label` set first labels every
|
|
281
|
+
* cluster). Only the attributes that decide how a cluster is drawn are copied.
|
|
282
|
+
*/
|
|
283
|
+
const INHERITED_GRAPH_ATTRIBUTES: ReadonlySet<string> = new Set([
|
|
284
|
+
"bgcolor",
|
|
285
|
+
"color",
|
|
286
|
+
"colorscheme",
|
|
287
|
+
"fillcolor",
|
|
288
|
+
"fontcolor",
|
|
289
|
+
"fontname",
|
|
290
|
+
"fontsize",
|
|
291
|
+
"gradientangle",
|
|
292
|
+
"label",
|
|
293
|
+
"labeljust",
|
|
294
|
+
"labelloc",
|
|
295
|
+
"pencolor",
|
|
296
|
+
"penwidth",
|
|
297
|
+
"peripheries",
|
|
298
|
+
"style",
|
|
299
|
+
"tooltip",
|
|
300
|
+
]);
|
|
267
301
|
|
|
268
302
|
/**
|
|
269
303
|
* The header keyword, ended by what may follow it in DOT: space, `{`, a quoted ID or a comment.
|
|
@@ -320,6 +354,8 @@ interface Scope {
|
|
|
320
354
|
readonly containers: number[];
|
|
321
355
|
/** Subgraph attributes buffered until the subgraph closes (the root applies them at once). */
|
|
322
356
|
readonly attributes: Map<string, DotAttribute>;
|
|
357
|
+
/** The drawing attributes a cluster opened in this scope inherits: the enclosing scopes' and this one's so far. */
|
|
358
|
+
readonly graphDefaults: Map<string, DotAttribute>;
|
|
323
359
|
/** Whether the subgraph is a cluster (by name or by `cluster=true`). */
|
|
324
360
|
cluster: boolean;
|
|
325
361
|
/** The container node index once created, or INVALID_INDEX. */
|
|
@@ -734,6 +770,12 @@ class DotParser {
|
|
|
734
770
|
/** The parent assigned to a node by this import. */
|
|
735
771
|
private readonly parentOf = new Map<number, number>();
|
|
736
772
|
|
|
773
|
+
/** Each cluster container's inherited drawing attributes, as its scope saw them when the cluster first opened. */
|
|
774
|
+
private readonly inherited = new Map<number, Map<string, DotAttribute>>();
|
|
775
|
+
|
|
776
|
+
/** The attributes each cluster container sets itself, which its inherited ones never replace. */
|
|
777
|
+
private readonly ownAttributes = new Map<number, Set<string>>();
|
|
778
|
+
|
|
737
779
|
/** Nodes already warned about a cluster conflict. */
|
|
738
780
|
private readonly conflictWarned = new Set<number>();
|
|
739
781
|
|
|
@@ -761,6 +803,16 @@ class DotParser {
|
|
|
761
803
|
|
|
762
804
|
private targetPortHandle: ColumnHandle = INVALID_INDEX as ColumnHandle;
|
|
763
805
|
|
|
806
|
+
private rankHandle: ColumnHandle = INVALID_INDEX as ColumnHandle; // NOSONAR(S2933): stringColumn assigns it through this[field]
|
|
807
|
+
|
|
808
|
+
private rankSetHandle: ColumnHandle = INVALID_INDEX as ColumnHandle; // NOSONAR(S2933): stringColumn assigns it through this[field]
|
|
809
|
+
|
|
810
|
+
/** The rank subgraph each node was put in first, by node index. */
|
|
811
|
+
private readonly rankSetOf = new Map<number, string>();
|
|
812
|
+
|
|
813
|
+
/** How many anonymous rank subgraphs were read, which names the next `%<n>`. */
|
|
814
|
+
private anonymousRanks = 0;
|
|
815
|
+
|
|
764
816
|
/** The current subgraph nesting depth. */
|
|
765
817
|
private depth = 0;
|
|
766
818
|
|
|
@@ -851,6 +903,7 @@ class DotParser {
|
|
|
851
903
|
});
|
|
852
904
|
const root = this.newScope(null, headerLine, true, null);
|
|
853
905
|
this.statementList(root);
|
|
906
|
+
this.applyInherited();
|
|
854
907
|
return lexer.next();
|
|
855
908
|
}
|
|
856
909
|
|
|
@@ -873,6 +926,7 @@ class DotParser {
|
|
|
873
926
|
memberSet: new Set(),
|
|
874
927
|
containers: [],
|
|
875
928
|
attributes: new Map(),
|
|
929
|
+
graphDefaults: new Map(parent?.graphDefaults),
|
|
876
930
|
cluster: false,
|
|
877
931
|
container: INVALID_INDEX,
|
|
878
932
|
};
|
|
@@ -1113,42 +1167,10 @@ class DotParser {
|
|
|
1113
1167
|
*/
|
|
1114
1168
|
private closeScope(scope: Scope, parent: Scope): void {
|
|
1115
1169
|
const { container } = scope;
|
|
1116
|
-
if (container
|
|
1117
|
-
|
|
1118
|
-
if (attribute.name !== CLUSTER_ATTRIBUTE) {
|
|
1119
|
-
this.setNodeAttribute(container, attribute.name, attribute.value, attribute.line);
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
for (const nested of scope.containers) {
|
|
1123
|
-
if (nested !== container && !this.parentOf.has(nested)) {
|
|
1124
|
-
this.setParent(nested, container);
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
for (const member of scope.members) {
|
|
1128
|
-
if (member === container) {
|
|
1129
|
-
continue;
|
|
1130
|
-
}
|
|
1131
|
-
const existing = this.parentOf.get(member);
|
|
1132
|
-
if (existing === undefined) {
|
|
1133
|
-
this.setParent(member, container);
|
|
1134
|
-
} else if (existing !== container && !this.isAncestor(container, existing)) {
|
|
1135
|
-
this.clusterConflict(member, existing, container, scope.line);
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
parent.containers.push(container);
|
|
1170
|
+
if (container === INVALID_INDEX) {
|
|
1171
|
+
this.closePlainSubgraph(scope, parent);
|
|
1139
1172
|
} else {
|
|
1140
|
-
|
|
1141
|
-
const names = [...scope.attributes.keys()].join(", ");
|
|
1142
|
-
this.report.warning(
|
|
1143
|
-
"unsupported",
|
|
1144
|
-
DOT_ISSUE.SUBGRAPH_ATTRIBUTES_DROPPED,
|
|
1145
|
-
`subgraph ${scope.name === null ? "(anonymous)" : JSON.stringify(scope.name)} is not a cluster; its attributes (${names}) cannot be represented and were dropped`,
|
|
1146
|
-
{ line: scope.line, element: scope.name },
|
|
1147
|
-
);
|
|
1148
|
-
}
|
|
1149
|
-
for (const nested of scope.containers) {
|
|
1150
|
-
parent.containers.push(nested);
|
|
1151
|
-
}
|
|
1173
|
+
this.closeCluster(scope, parent, container);
|
|
1152
1174
|
}
|
|
1153
1175
|
if (!parent.root) {
|
|
1154
1176
|
for (const member of scope.members) {
|
|
@@ -1160,6 +1182,88 @@ class DotParser {
|
|
|
1160
1182
|
}
|
|
1161
1183
|
}
|
|
1162
1184
|
|
|
1185
|
+
/**
|
|
1186
|
+
* Finish a cluster: apply its attributes to its container node, assign parents to its nested
|
|
1187
|
+
* containers and its members, and hand the container to the enclosing scope.
|
|
1188
|
+
* @param scope - the closed scope
|
|
1189
|
+
* @param parent - the enclosing scope
|
|
1190
|
+
* @param container - the cluster's container node
|
|
1191
|
+
*/
|
|
1192
|
+
private closeCluster(scope: Scope, parent: Scope, container: number): void {
|
|
1193
|
+
const own = this.ownAttributes.get(container) ?? new Set<string>();
|
|
1194
|
+
this.ownAttributes.set(container, own);
|
|
1195
|
+
for (const attribute of scope.attributes.values()) {
|
|
1196
|
+
if (attribute.name !== CLUSTER_ATTRIBUTE) {
|
|
1197
|
+
own.add(attribute.name);
|
|
1198
|
+
this.setNodeAttribute(container, attribute.name, attribute.value, attribute.line);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
for (const nested of scope.containers) {
|
|
1202
|
+
if (nested !== container && !this.parentOf.has(nested)) {
|
|
1203
|
+
this.setParent(nested, container);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
for (const member of scope.members) {
|
|
1207
|
+
if (member !== container) {
|
|
1208
|
+
this.adoptMember(member, container, scope.line);
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
parent.containers.push(container);
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
/**
|
|
1215
|
+
* Put a cluster's member in it, unless it is already in another cluster this one is not inside.
|
|
1216
|
+
* @param member - the member node
|
|
1217
|
+
* @param container - the cluster's container node
|
|
1218
|
+
* @param line - the cluster's line
|
|
1219
|
+
*/
|
|
1220
|
+
private adoptMember(member: number, container: number, line: number): void {
|
|
1221
|
+
const existing = this.parentOf.get(member);
|
|
1222
|
+
if (existing === undefined) {
|
|
1223
|
+
this.setParent(member, container);
|
|
1224
|
+
} else if (existing !== container && !this.isAncestor(container, existing)) {
|
|
1225
|
+
this.clusterConflict(member, existing, container, line);
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
/**
|
|
1230
|
+
* Finish a subgraph that is not a cluster: keep its rank, report its other attributes dropped, and hand its nested
|
|
1231
|
+
* containers to the enclosing scope.
|
|
1232
|
+
* @param scope - the closed scope
|
|
1233
|
+
* @param parent - the enclosing scope
|
|
1234
|
+
*/
|
|
1235
|
+
private closePlainSubgraph(scope: Scope, parent: Scope): void {
|
|
1236
|
+
const ranked = this.recordRank(scope);
|
|
1237
|
+
const dropped = [...scope.attributes.keys()].filter((name) => !(ranked && name === RANK_ATTRIBUTE));
|
|
1238
|
+
if (dropped.length > 0) {
|
|
1239
|
+
const names = dropped.join(", ");
|
|
1240
|
+
this.report.warning(
|
|
1241
|
+
"unsupported",
|
|
1242
|
+
DOT_ISSUE.SUBGRAPH_ATTRIBUTES_DROPPED,
|
|
1243
|
+
`subgraph ${scope.name === null ? "(anonymous)" : JSON.stringify(scope.name)} is not a cluster; its attributes (${names}) cannot be represented and were dropped`,
|
|
1244
|
+
{ line: scope.line, element: scope.name },
|
|
1245
|
+
);
|
|
1246
|
+
}
|
|
1247
|
+
for (const nested of scope.containers) {
|
|
1248
|
+
parent.containers.push(nested);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
/**
|
|
1253
|
+
* Give every cluster the drawing attributes it inherits and does not set itself (Graphviz's subgraph attribute
|
|
1254
|
+
* inheritance), once the whole graph is read: a cluster reopened later can still set its own.
|
|
1255
|
+
*/
|
|
1256
|
+
private applyInherited(): void {
|
|
1257
|
+
for (const [container, attributes] of this.inherited) {
|
|
1258
|
+
const own = this.ownAttributes.get(container);
|
|
1259
|
+
for (const attribute of attributes.values()) {
|
|
1260
|
+
if (own?.has(attribute.name) !== true) {
|
|
1261
|
+
this.setNodeAttribute(container, attribute.name, attribute.value, attribute.line);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1163
1267
|
/**
|
|
1164
1268
|
* Whether `candidate` is an ancestor of `node` through the parents assigned so far.
|
|
1165
1269
|
* @param candidate - the possible ancestor
|
|
@@ -1244,6 +1348,7 @@ class DotParser {
|
|
|
1244
1348
|
if (!this.containers.has(index)) {
|
|
1245
1349
|
this.containers.add(index);
|
|
1246
1350
|
this.sink.setNodeValue(this.clusterColumn(), index, true);
|
|
1351
|
+
this.inherited.set(index, new Map(scope.graphDefaults));
|
|
1247
1352
|
}
|
|
1248
1353
|
scope.container = index;
|
|
1249
1354
|
} catch (err) {
|
|
@@ -1261,6 +1366,9 @@ class DotParser {
|
|
|
1261
1366
|
* @param attribute - the attribute
|
|
1262
1367
|
*/
|
|
1263
1368
|
private scopeAttribute(scope: Scope, attribute: DotAttribute): void {
|
|
1369
|
+
if (INHERITED_GRAPH_ATTRIBUTES.has(attribute.name)) {
|
|
1370
|
+
scope.graphDefaults.set(attribute.name, attribute);
|
|
1371
|
+
}
|
|
1264
1372
|
if (scope.root) {
|
|
1265
1373
|
this.setGraphAttribute(attribute);
|
|
1266
1374
|
return;
|
|
@@ -1901,6 +2009,54 @@ class DotParser {
|
|
|
1901
2009
|
return this.positionHandle;
|
|
1902
2010
|
}
|
|
1903
2011
|
|
|
2012
|
+
/**
|
|
2013
|
+
* Keep a non-cluster subgraph's `rank` on its nodes: each gets the rank and the subgraph's name (`%<n>` for an
|
|
2014
|
+
* anonymous one). A node already in another rank subgraph keeps that one, with a warning.
|
|
2015
|
+
* @param scope - the closed subgraph
|
|
2016
|
+
* @returns true when the subgraph has a rank Graphviz knows
|
|
2017
|
+
*/
|
|
2018
|
+
private recordRank(scope: Scope): boolean {
|
|
2019
|
+
const rank = scope.attributes.get(RANK_ATTRIBUTE)?.value.trim();
|
|
2020
|
+
if (rank === undefined || !RANK_KINDS.has(rank)) {
|
|
2021
|
+
return false;
|
|
2022
|
+
}
|
|
2023
|
+
const set = scope.name ?? `%${this.anonymousRanks++}`;
|
|
2024
|
+
for (const member of scope.members) {
|
|
2025
|
+
const held = this.rankSetOf.get(member);
|
|
2026
|
+
const id = String(this.idOf.get(member) ?? member);
|
|
2027
|
+
if (held === undefined) {
|
|
2028
|
+
this.rankSetOf.set(member, set);
|
|
2029
|
+
try {
|
|
2030
|
+
this.sink.setNodeValue(this.stringColumn("rankHandle", RANK_COLUMN), member, rank);
|
|
2031
|
+
this.sink.setNodeValue(this.stringColumn("rankSetHandle", RANK_SET_COLUMN), member, set);
|
|
2032
|
+
} catch (err) {
|
|
2033
|
+
this.report.recordError(err, { element: id });
|
|
2034
|
+
}
|
|
2035
|
+
} else if (held !== set) {
|
|
2036
|
+
this.report.warning(
|
|
2037
|
+
"coercion",
|
|
2038
|
+
DOT_ISSUE.RANK_CONFLICT,
|
|
2039
|
+
`node ${JSON.stringify(id)} is in rank subgraph ${JSON.stringify(held)} and in rank subgraph ${JSON.stringify(set)}; the first is kept`,
|
|
2040
|
+
{ line: scope.line, element: id },
|
|
2041
|
+
);
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
return true;
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
/**
|
|
2048
|
+
* One of the importer's string node columns, declared on first use.
|
|
2049
|
+
* @param field - the field holding its handle
|
|
2050
|
+
* @param name - the column name
|
|
2051
|
+
* @returns the handle
|
|
2052
|
+
*/
|
|
2053
|
+
private stringColumn(field: "rankHandle" | "rankSetHandle", name: string): ColumnHandle {
|
|
2054
|
+
if (this[field] === INVALID_INDEX) {
|
|
2055
|
+
this[field] = this.declare("node", { name, dtype: "string", nullable: true, origin: DOT_ORIGIN });
|
|
2056
|
+
}
|
|
2057
|
+
return this[field];
|
|
2058
|
+
}
|
|
2059
|
+
|
|
1904
2060
|
/**
|
|
1905
2061
|
* The cluster marker column (bool).
|
|
1906
2062
|
* @returns the handle
|
package/src/formats/dot/index.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* @module @graphty/graph-io/dot
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
export type { BendPoint } from "../../styles/canon/bends.js";
|
|
7
8
|
export { DOT_LOSS, dotExporter, type DotExportOptions } from "./exporter.js";
|
|
8
9
|
export { DOT_ISSUE, dotImporter, type DotImportOptions } from "./importer.js";
|
|
9
|
-
export {
|
|
10
|
+
export { RANK_COLUMN, RANK_SET_COLUMN } from "./names.js";
|
|
11
|
+
export { DOT_STYLE_BLOCK_ATTRIBUTE, DOT_STYLE_CAPABILITIES, graphvizPosBends } from "./styles.js";
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where Graphviz puts an edge's labels: a stored `lp` (the label's center), and the head and tail labels at
|
|
3
|
+
* `head_lp` / `tail_lp` -- kept only with the edge's stored `pos` (`neato -n2` routes an edge without one again, and
|
|
4
|
+
* places its labels again) -- or where Graphviz's `place_portlabel` (lib/common/splines.c) puts them, when the edge's
|
|
5
|
+
* `labelangle` or `labeldistance` is not its default: `10 * labeldistance` points from the end of the line, turned
|
|
6
|
+
* `labelangle` degrees (default -25) from the line. With both at their defaults Graphviz places end labels as external
|
|
7
|
+
* labels, which graphty leaves to its own place beside the end. Read as offsets from where graphty puts each label:
|
|
8
|
+
* the edge label from the middle of its route, an end label from where the line meets its node.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { GraphSnapshot } from "@graphty/graph-format";
|
|
12
|
+
|
|
13
|
+
import { type BendPoint, flattenCubic } from "../../styles/canon/bends.js";
|
|
14
|
+
import { num6 } from "../../styles/canon/number.js";
|
|
15
|
+
import type { StyleValue } from "../../styles/types.js";
|
|
16
|
+
|
|
17
|
+
/** Graphviz's `PORT_LABEL_DISTANCE`, in points. */
|
|
18
|
+
const PORT_LABEL_DISTANCE = 10;
|
|
19
|
+
|
|
20
|
+
/** Graphviz's `PORT_LABEL_ANGLE`, in degrees. */
|
|
21
|
+
const PORT_LABEL_ANGLE = -25;
|
|
22
|
+
|
|
23
|
+
/** Graphviz's default node size, in inches. */
|
|
24
|
+
const DEFAULT_SIZE = { w: 0.75, h: 0.5 } as const;
|
|
25
|
+
|
|
26
|
+
/** One attribute of an element as text, or null when it is unset. */
|
|
27
|
+
type Attr = (name: string) => string | null;
|
|
28
|
+
|
|
29
|
+
/** Receives one property's value. */
|
|
30
|
+
type Put = (property: string, value: StyleValue | null) => void;
|
|
31
|
+
|
|
32
|
+
/** What the label places of one graph's edges are read against. */
|
|
33
|
+
export interface LabelPlaceContext {
|
|
34
|
+
/** A node's center from its position, in points, y up. */
|
|
35
|
+
readonly center: (n: number) => BendPoint | null;
|
|
36
|
+
/** A node's attribute. */
|
|
37
|
+
readonly node: (n: number, name: string) => string | null;
|
|
38
|
+
/**
|
|
39
|
+
* Whether the layout engine places an edge label it was not given as an external label (every engine but `dot`,
|
|
40
|
+
* which ranks a label as a node of its own): lib/common/postproc.c `addXLabels` takes each unplaced edge label as
|
|
41
|
+
* an xlabel of the edge's middle, and lib/label/xlabels.c puts it, where nothing else is drawn, up and to the left
|
|
42
|
+
* of that point, its box's lower right corner on it.
|
|
43
|
+
*/
|
|
44
|
+
readonly external: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Reads an edge's stored label places and its head and tail label places as offsets.
|
|
49
|
+
* @param snapshot - the graph
|
|
50
|
+
* @param cx - the graph's label place context
|
|
51
|
+
* @param e - the edge
|
|
52
|
+
* @param get - the edge's attributes
|
|
53
|
+
* @param put - receives the values
|
|
54
|
+
*/
|
|
55
|
+
export function readLabelPlaces(snapshot: GraphSnapshot, cx: LabelPlaceContext, e: number, get: Attr, put: Put): void {
|
|
56
|
+
const s = snapshot.edgeSource(e);
|
|
57
|
+
const t = snapshot.edgeTarget(e);
|
|
58
|
+
const [source, target] = [cx.center(s), cx.center(t)];
|
|
59
|
+
const route = source === null || target === null ? null : edgeRoute(source, target, get("pos"));
|
|
60
|
+
const lp = (route?.start ?? null) === null ? null : point(get("lp"));
|
|
61
|
+
if (lp === null && cx.external && s !== t && (get("label") ?? get("xlabel")) !== null) {
|
|
62
|
+
// ponytail: the first place xlabels.c tries; one that would cover another label or node moves elsewhere
|
|
63
|
+
put("labelPosition", "center");
|
|
64
|
+
put("labelShiftX", -0.5);
|
|
65
|
+
put("labelShiftY", -0.5);
|
|
66
|
+
}
|
|
67
|
+
if (route === null || source === null || target === null || s === t) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (lp !== null && get("label") !== null) {
|
|
71
|
+
const mid = routeMiddle(route.points);
|
|
72
|
+
put("labelOffsetX", num6(lp[0] - mid[0]));
|
|
73
|
+
put("labelOffsetY", num6(mid[1] - lp[1]));
|
|
74
|
+
}
|
|
75
|
+
readEndLabel(cx, route, { node: t, at: target, other: source }, "head", get, put);
|
|
76
|
+
readEndLabel(cx, route, { node: s, at: source, other: target }, "tail", get, put);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** One end of an edge: its node, that node's center and the other end's center. */
|
|
80
|
+
interface EdgeEnd {
|
|
81
|
+
readonly node: number;
|
|
82
|
+
readonly at: BendPoint;
|
|
83
|
+
readonly other: BendPoint;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Reads one end's label place as an offset from where its line meets its node.
|
|
88
|
+
* @param cx - the graph's label place context
|
|
89
|
+
* @param route - the edge's route
|
|
90
|
+
* @param end - the end's node and the two centers
|
|
91
|
+
* @param which - which end
|
|
92
|
+
* @param get - the edge's attributes
|
|
93
|
+
* @param put - receives the values
|
|
94
|
+
*/
|
|
95
|
+
function readEndLabel(
|
|
96
|
+
cx: LabelPlaceContext,
|
|
97
|
+
route: EdgeRoute,
|
|
98
|
+
end: EdgeEnd,
|
|
99
|
+
which: "head" | "tail",
|
|
100
|
+
get: Attr,
|
|
101
|
+
put: Put,
|
|
102
|
+
): void {
|
|
103
|
+
if (get(`${which}label`) === null) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const head = which === "head";
|
|
107
|
+
const tip = (head ? route.end : route.start) ?? boundary(cx, end.node, end.at, end.other);
|
|
108
|
+
// the nearest route point back from the end that is not the end itself (a spline with no arrow ends at it);
|
|
109
|
+
// the route's last point is the node's center, past the end
|
|
110
|
+
const back = head ? route.points.slice(0, -1).reverse() : route.points.slice(1);
|
|
111
|
+
const toward = back.find((p) => Math.hypot(p[0] - tip[0], p[1] - tip[1]) > 1e-6) ?? end.other;
|
|
112
|
+
const stored = route.start === null ? null : point(get(`${which}_lp`));
|
|
113
|
+
const at = stored ?? portLabel(get, tip, toward);
|
|
114
|
+
if (at !== null) {
|
|
115
|
+
const prefix = head ? "target" : "source";
|
|
116
|
+
put(`${prefix}LabelOffset`, 0);
|
|
117
|
+
put(`${prefix}LabelOffsetX`, num6(at[0] - tip[0]));
|
|
118
|
+
put(`${prefix}LabelOffsetY`, num6(tip[1] - at[1]));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Where Graphviz's `place_portlabel` puts an end label's center: only when the edge's `labelangle` or
|
|
124
|
+
* `labeldistance` is not its default.
|
|
125
|
+
* @param get - the edge's attributes
|
|
126
|
+
* @param tip - the end of the line
|
|
127
|
+
* @param toward - a point back along the line from the end
|
|
128
|
+
* @returns the center, or null when Graphviz places the label as an external label
|
|
129
|
+
*/
|
|
130
|
+
function portLabel(get: Attr, tip: BendPoint, toward: BendPoint): BendPoint | null {
|
|
131
|
+
const turn = finite(get("labelangle"), PORT_LABEL_ANGLE, -180);
|
|
132
|
+
const distance = finite(get("labeldistance"), 1, 0);
|
|
133
|
+
if (turn === PORT_LABEL_ANGLE && distance === 1) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
const angle = Math.atan2(toward[1] - tip[1], toward[0] - tip[0]) + (turn * Math.PI) / 180;
|
|
137
|
+
const dist = PORT_LABEL_DISTANCE * distance;
|
|
138
|
+
return [tip[0] + dist * Math.cos(angle), tip[1] + dist * Math.sin(angle)];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* A number attribute as Graphviz's `late_double` reads it: the default when unset or not a number, at least `low`.
|
|
143
|
+
* @param raw - the value
|
|
144
|
+
* @param fallback - the default
|
|
145
|
+
* @param low - the least value
|
|
146
|
+
* @returns the number
|
|
147
|
+
*/
|
|
148
|
+
function finite(raw: string | null, fallback: number, low: number): number {
|
|
149
|
+
const v = raw === null || raw.trim() === "" ? Number.NaN : Number(raw);
|
|
150
|
+
return Number.isFinite(v) ? Math.max(low, v) : fallback;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* An "x,y" point (a trailing `!` allowed).
|
|
155
|
+
* @param raw - the text
|
|
156
|
+
* @returns the point, or null
|
|
157
|
+
*/
|
|
158
|
+
function point(raw: string | null): BendPoint | null {
|
|
159
|
+
const parts = (raw ?? "").replace(/!$/, "").split(",").map(Number);
|
|
160
|
+
return parts.length >= 2 && Number.isFinite(parts[0]) && Number.isFinite(parts[1]) ? [parts[0], parts[1]] : null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** An edge's route: its points from center to center, and the ends of its line when stored. */
|
|
164
|
+
interface EdgeRoute {
|
|
165
|
+
readonly points: BendPoint[];
|
|
166
|
+
readonly start: BendPoint | null;
|
|
167
|
+
readonly end: BendPoint | null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* The route an edge is drawn along: its stored spline's points (flattened) between the two centers, and the ends of
|
|
172
|
+
* its line where `pos` gives arrow points (`s,` / `e,`) or its spline's own ends.
|
|
173
|
+
* @param source - the source's center
|
|
174
|
+
* @param target - the target's center
|
|
175
|
+
* @param pos - the edge's `pos`
|
|
176
|
+
* @returns the route
|
|
177
|
+
*/
|
|
178
|
+
function edgeRoute(source: BendPoint, target: BendPoint, pos: string | null): EdgeRoute {
|
|
179
|
+
const tokens = (pos ?? "").split(";")[0].trim().split(/\s+/).filter(Boolean);
|
|
180
|
+
const marked = (flag: string): BendPoint | null => {
|
|
181
|
+
const token = tokens.find((x) => x.startsWith(`${flag},`));
|
|
182
|
+
return token === undefined ? null : point(token.slice(2));
|
|
183
|
+
};
|
|
184
|
+
const controls = tokens.filter((x) => !/^[es],/.test(x)).map((x) => point(x));
|
|
185
|
+
const flat = controls.every((p) => p !== null) && controls.length >= 4 ? flattenCubic(controls) : null;
|
|
186
|
+
if (flat === null) {
|
|
187
|
+
return { points: [source, target], start: null, end: null };
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
points: [source, ...flat, target],
|
|
191
|
+
start: marked("s") ?? flat[0],
|
|
192
|
+
end: marked("e") ?? flat.at(-1) ?? null,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* The point halfway along a route.
|
|
198
|
+
* @param points - the route
|
|
199
|
+
* @returns the point
|
|
200
|
+
*/
|
|
201
|
+
function routeMiddle(points: readonly BendPoint[]): BendPoint {
|
|
202
|
+
// ponytail: halfway by length; graphty puts a bent edge's label at its middle segment, close to it
|
|
203
|
+
const lengths = points.slice(1).map((p, i) => Math.hypot(p[0] - points[i][0], p[1] - points[i][1]));
|
|
204
|
+
let left = lengths.reduce((a, b) => a + b, 0) / 2;
|
|
205
|
+
for (let i = 0; i < lengths.length; i++) {
|
|
206
|
+
if (left <= lengths[i] && lengths[i] > 0) {
|
|
207
|
+
const f = left / lengths[i];
|
|
208
|
+
return [
|
|
209
|
+
points[i][0] + f * (points[i + 1][0] - points[i][0]),
|
|
210
|
+
points[i][1] + f * (points[i + 1][1] - points[i][1]),
|
|
211
|
+
];
|
|
212
|
+
}
|
|
213
|
+
left -= lengths[i];
|
|
214
|
+
}
|
|
215
|
+
return points[0];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Where the straight line from a node's center toward a point leaves the node, the node taken as the ellipse of its
|
|
220
|
+
* `width` and `height`.
|
|
221
|
+
* @param cx - the label place context
|
|
222
|
+
* @param n - the node
|
|
223
|
+
* @param center - its center
|
|
224
|
+
* @param toward - the point
|
|
225
|
+
* @returns the point on its outline
|
|
226
|
+
*/
|
|
227
|
+
function boundary(cx: LabelPlaceContext, n: number, center: BendPoint, toward: BendPoint): BendPoint {
|
|
228
|
+
// ponytail: every shape taken as its ellipse; exact for the circles and ellipses the end labels sit on
|
|
229
|
+
const inch = (name: "width" | "height", fallback: number): number => {
|
|
230
|
+
const v = Number(cx.node(n, name) ?? Number.NaN);
|
|
231
|
+
return (Number.isFinite(v) && v >= 0 ? v : fallback) * 72;
|
|
232
|
+
};
|
|
233
|
+
const [rx, ry] = [inch("width", DEFAULT_SIZE.w) / 2, inch("height", DEFAULT_SIZE.h) / 2];
|
|
234
|
+
const [dx, dy] = [toward[0] - center[0], toward[1] - center[1]];
|
|
235
|
+
const len = Math.hypot(dx, dy);
|
|
236
|
+
if (len === 0 || rx === 0 || ry === 0) {
|
|
237
|
+
return center;
|
|
238
|
+
}
|
|
239
|
+
const r = 1 / Math.hypot(dx / len / rx, dy / len / ry);
|
|
240
|
+
return [center[0] + (dx / len) * r, center[1] + (dy / len) * r];
|
|
241
|
+
}
|
package/src/formats/dot/names.ts
CHANGED
|
@@ -77,3 +77,18 @@ export const PIN_ATTRIBUTE = "pin";
|
|
|
77
77
|
* @category Plugin helpers
|
|
78
78
|
*/
|
|
79
79
|
export const DOT_META_KEY = "dot";
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The string node column holding the `rank` of the non-cluster subgraph a node is in (`same`,
|
|
83
|
+
* `min`, `max`, `source` or `sink`): Graphviz's dot puts the subgraph's nodes on one rank, or on
|
|
84
|
+
* the first or last. Set only on nodes of such a subgraph.
|
|
85
|
+
* @category Plugin helpers
|
|
86
|
+
*/
|
|
87
|
+
export const RANK_COLUMN = "graphty.rank";
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The string node column naming the rank subgraph a node is in (`graphty.rank`): the subgraph's
|
|
91
|
+
* name, or `%<n>` for the n-th anonymous one, so the nodes of one subgraph share a value.
|
|
92
|
+
* @category Plugin helpers
|
|
93
|
+
*/
|
|
94
|
+
export const RANK_SET_COLUMN = "graphty.rankSet";
|