@graphty/graph-io 0.3.42 → 0.3.44
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-3Q4TsdTh.js +40 -0
- package/dist/chunks/approximations-3Q4TsdTh.js.map +1 -0
- package/dist/chunks/block-JQiwViEt.js +2777 -0
- package/dist/chunks/block-JQiwViEt.js.map +1 -0
- package/dist/chunks/{choose-DvpbdRuz.js → choose-BemygfH8.js} +3 -2
- package/dist/chunks/{choose-DvpbdRuz.js.map → choose-BemygfH8.js.map} +1 -1
- package/dist/chunks/{constants-fT3E8JYY.js → constants-BFUR_CtU.js} +6 -2
- package/dist/chunks/constants-BFUR_CtU.js.map +1 -0
- package/dist/chunks/convert-BcQ8_jMo.js +59 -0
- package/dist/chunks/convert-BcQ8_jMo.js.map +1 -0
- package/dist/chunks/emit-DCwFLts5.js +3456 -0
- package/dist/chunks/emit-DCwFLts5.js.map +1 -0
- package/dist/chunks/{escape-B62ZGM_a.js → escape-B1rMftd9.js} +43 -20
- package/dist/chunks/escape-B1rMftd9.js.map +1 -0
- package/dist/chunks/{export-rKLeGQMo.js → export-D7IGzTG4.js} +196 -792
- package/dist/chunks/export-D7IGzTG4.js.map +1 -0
- package/dist/chunks/{exporter-BWwEuOPT.js → exporter-BtnqYuuj.js} +22 -12
- package/dist/chunks/exporter-BtnqYuuj.js.map +1 -0
- package/dist/chunks/{exporter-yLxKBvLE.js → exporter-ChPyhBOv.js} +4 -3
- package/dist/chunks/{exporter-yLxKBvLE.js.map → exporter-ChPyhBOv.js.map} +1 -1
- package/dist/chunks/{exporter-8hLNemFk.js → exporter-KEPxYUXD.js} +133 -74
- package/dist/chunks/exporter-KEPxYUXD.js.map +1 -0
- package/dist/chunks/{exporter-CpRyHZ3H.js → exporter-quPUCBiC.js} +1807 -288
- package/dist/chunks/exporter-quPUCBiC.js.map +1 -0
- package/dist/chunks/format-GDmO6m6Q.js +676 -0
- package/dist/chunks/format-GDmO6m6Q.js.map +1 -0
- package/dist/chunks/generic-BL06jrJf.js +1347 -0
- package/dist/chunks/generic-BL06jrJf.js.map +1 -0
- package/dist/chunks/{importer-WrGRZb0N.js → importer-B7r2owVf.js} +449 -102
- package/dist/chunks/importer-B7r2owVf.js.map +1 -0
- package/dist/chunks/{importer-Ht7LNg8L.js → importer-BFmOP96W.js} +116 -296
- package/dist/chunks/importer-BFmOP96W.js.map +1 -0
- package/dist/chunks/{importer-BbNb7eNg.js → importer-C2nzGhdV.js} +1390 -129
- package/dist/chunks/importer-C2nzGhdV.js.map +1 -0
- package/dist/chunks/{importer-Dz7tI8Sa.js → importer-CbX2_rNF.js} +617 -115
- package/dist/chunks/importer-CbX2_rNF.js.map +1 -0
- package/dist/chunks/{importer-D794XUTe.js → importer-CdzeN6X4.js} +31 -8
- package/dist/chunks/importer-CdzeN6X4.js.map +1 -0
- package/dist/chunks/{importer-xZ-3suY1.js → importer-ChKNC_GN.js} +791 -135
- package/dist/chunks/importer-ChKNC_GN.js.map +1 -0
- package/dist/chunks/{importer-C98dpSH4.js → importer-dwoYpSqb.js} +141 -82
- package/dist/chunks/importer-dwoYpSqb.js.map +1 -0
- package/dist/chunks/index-B9fdNpTA.js +4310 -0
- package/dist/chunks/index-B9fdNpTA.js.map +1 -0
- package/dist/chunks/{json-elements-DKSqpNW1.js → json-elements-C4FwgnH5.js} +123 -32
- package/dist/chunks/json-elements-C4FwgnH5.js.map +1 -0
- package/dist/chunks/lexicon-B-knUi-l.js +508 -0
- package/dist/chunks/lexicon-B-knUi-l.js.map +1 -0
- package/dist/chunks/{ontology-export-CtRXjg_i.js → ontology-export-BSpbY5FL.js} +3 -2
- package/dist/chunks/{ontology-export-CtRXjg_i.js.map → ontology-export-BSpbY5FL.js.map} +1 -1
- package/dist/chunks/{records-Cu4bxYOm.js → records-Nwz_rbNt.js} +2 -2
- package/dist/chunks/{records-Cu4bxYOm.js.map → records-Nwz_rbNt.js.map} +1 -1
- package/dist/chunks/styles-Brt9JMfs.js +690 -0
- package/dist/chunks/styles-Brt9JMfs.js.map +1 -0
- package/dist/chunks/styles-_N-C8S-U.js +2102 -0
- package/dist/chunks/styles-_N-C8S-U.js.map +1 -0
- package/dist/chunks/styles-yed-DAfcIkf7.js +842 -0
- package/dist/chunks/styles-yed-DAfcIkf7.js.map +1 -0
- package/dist/chunks/{text-DHOJXnED.js → text-CgzMqHQb.js} +2 -2
- package/dist/chunks/{text-DHOJXnED.js.map → text-CgzMqHQb.js.map} +1 -1
- package/dist/chunks/units-XMZFIFe1.js +19 -0
- package/dist/chunks/units-XMZFIFe1.js.map +1 -0
- package/dist/csv.js +5 -4
- package/dist/csv.js.map +1 -1
- package/dist/cx.js +1 -1
- package/dist/cx2.js +2 -2
- package/dist/cys.js +1 -1
- package/dist/dot.js +5 -2
- package/dist/dot.js.map +1 -1
- package/dist/gexf.js +295 -414
- package/dist/gexf.js.map +1 -1
- package/dist/gml.js +8 -3031
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +354 -240
- package/dist/graph-io.js.map +1 -1
- package/dist/graphml.js +4 -2
- package/dist/graphml.js.map +1 -1
- package/dist/json.js +1 -1
- package/dist/neo4j.js +4 -3
- package/dist/neo4j.js.map +1 -1
- package/dist/obo.js +1 -1
- package/dist/pajek.js +4 -2
- package/dist/positions.d.ts +1 -0
- package/dist/positions.js +427 -0
- package/dist/positions.js.map +1 -0
- package/dist/src/common/codes.d.ts +6 -0
- package/dist/src/common/codes.d.ts.map +1 -1
- package/dist/src/common/codes.js +6 -0
- package/dist/src/common/codes.js.map +1 -1
- package/dist/src/common/escape.d.ts.map +1 -1
- package/dist/src/common/escape.js +4 -2
- package/dist/src/common/escape.js.map +1 -1
- package/dist/src/common/export.d.ts +10 -0
- package/dist/src/common/export.d.ts.map +1 -1
- package/dist/src/common/export.js +123 -100
- package/dist/src/common/export.js.map +1 -1
- package/dist/src/common/input.d.ts.map +1 -1
- package/dist/src/common/input.js +8 -1
- package/dist/src/common/input.js.map +1 -1
- package/dist/src/common/json-elements.d.ts +12 -9
- package/dist/src/common/json-elements.d.ts.map +1 -1
- package/dist/src/common/json-elements.js +160 -37
- package/dist/src/common/json-elements.js.map +1 -1
- package/dist/src/common/notes.d.ts +42 -0
- package/dist/src/common/notes.d.ts.map +1 -0
- package/dist/src/common/notes.js +72 -0
- package/dist/src/common/notes.js.map +1 -0
- package/dist/src/common/report.d.ts +18 -0
- package/dist/src/common/report.d.ts.map +1 -1
- package/dist/src/common/report.js +36 -1
- package/dist/src/common/report.js.map +1 -1
- package/dist/src/common/units.d.ts +24 -0
- package/dist/src/common/units.d.ts.map +1 -0
- package/dist/src/common/units.js +26 -0
- package/dist/src/common/units.js.map +1 -0
- package/dist/src/common/xml.d.ts +18 -0
- package/dist/src/common/xml.d.ts.map +1 -1
- package/dist/src/common/xml.js +42 -5
- package/dist/src/common/xml.js.map +1 -1
- package/dist/src/formats/cx/exporter.d.ts +6 -0
- package/dist/src/formats/cx/exporter.d.ts.map +1 -1
- package/dist/src/formats/cx/exporter.js +71 -8
- package/dist/src/formats/cx/exporter.js.map +1 -1
- package/dist/src/formats/cx/importer.d.ts +5 -2
- package/dist/src/formats/cx/importer.d.ts.map +1 -1
- package/dist/src/formats/cx/importer.js +102 -72
- package/dist/src/formats/cx/importer.js.map +1 -1
- package/dist/src/formats/cx/styles.d.ts +102 -0
- package/dist/src/formats/cx/styles.d.ts.map +1 -0
- package/dist/src/formats/cx/styles.js +225 -0
- package/dist/src/formats/cx/styles.js.map +1 -0
- package/dist/src/formats/cx2/exporter.d.ts +5 -0
- package/dist/src/formats/cx2/exporter.d.ts.map +1 -1
- package/dist/src/formats/cx2/exporter.js +181 -71
- package/dist/src/formats/cx2/exporter.js.map +1 -1
- package/dist/src/formats/cx2/importer.d.ts +4 -1
- package/dist/src/formats/cx2/importer.d.ts.map +1 -1
- package/dist/src/formats/cx2/importer.js +19 -1
- package/dist/src/formats/cx2/importer.js.map +1 -1
- package/dist/src/formats/cx2/styles.d.ts +18 -0
- package/dist/src/formats/cx2/styles.d.ts.map +1 -0
- package/dist/src/formats/cx2/styles.js +24 -0
- package/dist/src/formats/cx2/styles.js.map +1 -0
- package/dist/src/formats/cys/constants.d.ts +2 -0
- package/dist/src/formats/cys/constants.d.ts.map +1 -1
- package/dist/src/formats/cys/constants.js +2 -0
- package/dist/src/formats/cys/constants.js.map +1 -1
- package/dist/src/formats/cys/exporter.d.ts +6 -2
- package/dist/src/formats/cys/exporter.d.ts.map +1 -1
- package/dist/src/formats/cys/exporter.js +215 -53
- package/dist/src/formats/cys/exporter.js.map +1 -1
- package/dist/src/formats/cys/importer.d.ts +2 -1
- package/dist/src/formats/cys/importer.d.ts.map +1 -1
- package/dist/src/formats/cys/importer.js +119 -6
- package/dist/src/formats/cys/importer.js.map +1 -1
- package/dist/src/formats/cys/session.d.ts +2 -0
- package/dist/src/formats/cys/session.d.ts.map +1 -1
- package/dist/src/formats/cys/session.js +5 -0
- package/dist/src/formats/cys/session.js.map +1 -1
- package/dist/src/formats/cys/styles.d.ts +38 -0
- package/dist/src/formats/cys/styles.d.ts.map +1 -0
- package/dist/src/formats/cys/styles.js +213 -0
- package/dist/src/formats/cys/styles.js.map +1 -0
- package/dist/src/formats/cys/tables.d.ts +8 -3
- package/dist/src/formats/cys/tables.d.ts.map +1 -1
- package/dist/src/formats/cys/tables.js +88 -34
- package/dist/src/formats/cys/tables.js.map +1 -1
- package/dist/src/formats/dot/exporter.d.ts +2 -0
- package/dist/src/formats/dot/exporter.d.ts.map +1 -1
- package/dist/src/formats/dot/exporter.js +195 -81
- package/dist/src/formats/dot/exporter.js.map +1 -1
- package/dist/src/formats/dot/importer.d.ts.map +1 -1
- package/dist/src/formats/dot/importer.js +100 -20
- package/dist/src/formats/dot/importer.js.map +1 -1
- package/dist/src/formats/dot/index.d.ts +1 -0
- package/dist/src/formats/dot/index.d.ts.map +1 -1
- package/dist/src/formats/dot/index.js +1 -0
- package/dist/src/formats/dot/index.js.map +1 -1
- package/dist/src/formats/dot/positions.d.ts +14 -0
- package/dist/src/formats/dot/positions.d.ts.map +1 -0
- package/dist/src/formats/dot/positions.js +70 -0
- package/dist/src/formats/dot/positions.js.map +1 -0
- package/dist/src/formats/dot/styles.d.ts +82 -0
- package/dist/src/formats/dot/styles.d.ts.map +1 -0
- package/dist/src/formats/dot/styles.js +1484 -0
- package/dist/src/formats/dot/styles.js.map +1 -0
- package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
- package/dist/src/formats/gexf/exporter.js +23 -7
- package/dist/src/formats/gexf/exporter.js.map +1 -1
- package/dist/src/formats/gexf/importer.d.ts +8 -1
- package/dist/src/formats/gexf/importer.d.ts.map +1 -1
- package/dist/src/formats/gexf/importer.js +251 -131
- package/dist/src/formats/gexf/importer.js.map +1 -1
- package/dist/src/formats/gexf/index.d.ts +8 -0
- package/dist/src/formats/gexf/index.d.ts.map +1 -1
- package/dist/src/formats/gexf/index.js +10 -2
- package/dist/src/formats/gexf/index.js.map +1 -1
- package/dist/src/formats/gexf/schema.d.ts +5 -0
- package/dist/src/formats/gexf/schema.d.ts.map +1 -1
- package/dist/src/formats/gexf/schema.js +5 -0
- package/dist/src/formats/gexf/schema.js.map +1 -1
- package/dist/src/formats/gexf/styles.d.ts +74 -0
- package/dist/src/formats/gexf/styles.d.ts.map +1 -0
- package/dist/src/formats/gexf/styles.js +604 -0
- package/dist/src/formats/gexf/styles.js.map +1 -0
- package/dist/src/formats/gml/exporter.d.ts +1 -5
- package/dist/src/formats/gml/exporter.d.ts.map +1 -1
- package/dist/src/formats/gml/exporter.js +19 -8
- package/dist/src/formats/gml/exporter.js.map +1 -1
- package/dist/src/formats/gml/importer.d.ts.map +1 -1
- package/dist/src/formats/gml/importer.js +4 -0
- package/dist/src/formats/gml/importer.js.map +1 -1
- package/dist/src/formats/gml/index.d.ts +2 -1
- package/dist/src/formats/gml/index.d.ts.map +1 -1
- package/dist/src/formats/gml/index.js +2 -1
- package/dist/src/formats/gml/index.js.map +1 -1
- package/dist/src/formats/gml/positions.d.ts +14 -0
- package/dist/src/formats/gml/positions.d.ts.map +1 -0
- package/dist/src/formats/gml/positions.js +46 -0
- package/dist/src/formats/gml/positions.js.map +1 -0
- package/dist/src/formats/gml/styles.d.ts +59 -0
- package/dist/src/formats/gml/styles.d.ts.map +1 -0
- package/dist/src/formats/gml/styles.js +1056 -0
- package/dist/src/formats/gml/styles.js.map +1 -0
- package/dist/src/formats/gml/syntax.d.ts +11 -0
- package/dist/src/formats/gml/syntax.d.ts.map +1 -1
- package/dist/src/formats/gml/syntax.js +151 -62
- package/dist/src/formats/gml/syntax.js.map +1 -1
- package/dist/src/formats/graphml/constants.d.ts +4 -0
- package/dist/src/formats/graphml/constants.d.ts.map +1 -1
- package/dist/src/formats/graphml/constants.js +5 -1
- package/dist/src/formats/graphml/constants.js.map +1 -1
- package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
- package/dist/src/formats/graphml/exporter.js +133 -65
- package/dist/src/formats/graphml/exporter.js.map +1 -1
- package/dist/src/formats/graphml/importer.d.ts +4 -1
- package/dist/src/formats/graphml/importer.d.ts.map +1 -1
- package/dist/src/formats/graphml/importer.js +100 -44
- package/dist/src/formats/graphml/importer.js.map +1 -1
- package/dist/src/formats/graphml/index.d.ts +1 -0
- package/dist/src/formats/graphml/index.d.ts.map +1 -1
- package/dist/src/formats/graphml/index.js +1 -0
- package/dist/src/formats/graphml/index.js.map +1 -1
- package/dist/src/formats/graphml/styles-plain.d.ts +19 -0
- package/dist/src/formats/graphml/styles-plain.d.ts.map +1 -0
- package/dist/src/formats/graphml/styles-plain.js +187 -0
- package/dist/src/formats/graphml/styles-plain.js.map +1 -0
- package/dist/src/formats/graphml/styles-yed.d.ts +179 -0
- package/dist/src/formats/graphml/styles-yed.d.ts.map +1 -0
- package/dist/src/formats/graphml/styles-yed.js +1086 -0
- package/dist/src/formats/graphml/styles-yed.js.map +1 -0
- package/dist/src/formats/graphml/styles-yfiles3.d.ts +19 -0
- package/dist/src/formats/graphml/styles-yfiles3.d.ts.map +1 -0
- package/dist/src/formats/graphml/styles-yfiles3.js +508 -0
- package/dist/src/formats/graphml/styles-yfiles3.js.map +1 -0
- package/dist/src/formats/graphml/tree.d.ts.map +1 -1
- package/dist/src/formats/graphml/tree.js +34 -19
- package/dist/src/formats/graphml/tree.js.map +1 -1
- package/dist/src/formats/graphml/yfiles.d.ts +16 -2
- package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
- package/dist/src/formats/graphml/yfiles.js +83 -12
- package/dist/src/formats/graphml/yfiles.js.map +1 -1
- package/dist/src/formats/json/exporter.d.ts +5 -0
- package/dist/src/formats/json/exporter.d.ts.map +1 -1
- package/dist/src/formats/json/exporter.js +68 -25
- package/dist/src/formats/json/exporter.js.map +1 -1
- package/dist/src/formats/json/importer.d.ts +22 -3
- package/dist/src/formats/json/importer.d.ts.map +1 -1
- package/dist/src/formats/json/importer.js +441 -265
- package/dist/src/formats/json/importer.js.map +1 -1
- package/dist/src/formats/json/positions.d.ts +16 -0
- package/dist/src/formats/json/positions.d.ts.map +1 -0
- package/dist/src/formats/json/positions.js +44 -0
- package/dist/src/formats/json/positions.js.map +1 -0
- package/dist/src/formats/json/styles.d.ts +102 -0
- package/dist/src/formats/json/styles.d.ts.map +1 -0
- package/dist/src/formats/json/styles.js +1753 -0
- package/dist/src/formats/json/styles.js.map +1 -0
- package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
- package/dist/src/formats/neo4j/exporter.js +2 -1
- package/dist/src/formats/neo4j/exporter.js.map +1 -1
- package/dist/src/formats/pajek/exporter.d.ts +2 -0
- package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
- package/dist/src/formats/pajek/exporter.js +142 -76
- package/dist/src/formats/pajek/exporter.js.map +1 -1
- package/dist/src/formats/pajek/importer.d.ts +4 -0
- package/dist/src/formats/pajek/importer.d.ts.map +1 -1
- package/dist/src/formats/pajek/importer.js +60 -6
- package/dist/src/formats/pajek/importer.js.map +1 -1
- package/dist/src/formats/pajek/index.d.ts +2 -0
- package/dist/src/formats/pajek/index.d.ts.map +1 -1
- package/dist/src/formats/pajek/index.js +2 -0
- package/dist/src/formats/pajek/index.js.map +1 -1
- package/dist/src/formats/pajek/styles.d.ts +50 -0
- package/dist/src/formats/pajek/styles.d.ts.map +1 -0
- package/dist/src/formats/pajek/styles.js +569 -0
- package/dist/src/formats/pajek/styles.js.map +1 -0
- package/dist/src/formats/pajek/syntax.d.ts +6 -0
- package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
- package/dist/src/formats/pajek/syntax.js +6 -0
- package/dist/src/formats/pajek/syntax.js.map +1 -1
- package/dist/src/formats/xgmml/columns.d.ts.map +1 -1
- package/dist/src/formats/xgmml/columns.js +34 -9
- package/dist/src/formats/xgmml/columns.js.map +1 -1
- package/dist/src/formats/xgmml/constants.d.ts +2 -0
- package/dist/src/formats/xgmml/constants.d.ts.map +1 -1
- package/dist/src/formats/xgmml/constants.js +3 -1
- package/dist/src/formats/xgmml/constants.js.map +1 -1
- package/dist/src/formats/xgmml/document.d.ts +12 -8
- package/dist/src/formats/xgmml/document.d.ts.map +1 -1
- package/dist/src/formats/xgmml/document.js +56 -13
- package/dist/src/formats/xgmml/document.js.map +1 -1
- package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
- package/dist/src/formats/xgmml/emit.js +12 -6
- package/dist/src/formats/xgmml/emit.js.map +1 -1
- package/dist/src/formats/xgmml/exporter.d.ts +3 -1
- package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
- package/dist/src/formats/xgmml/exporter.js +22 -9
- package/dist/src/formats/xgmml/exporter.js.map +1 -1
- package/dist/src/formats/xgmml/importer.d.ts +2 -1
- package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
- package/dist/src/formats/xgmml/importer.js +31 -24
- package/dist/src/formats/xgmml/importer.js.map +1 -1
- package/dist/src/formats/xgmml/styles.d.ts +104 -0
- package/dist/src/formats/xgmml/styles.d.ts.map +1 -0
- package/dist/src/formats/xgmml/styles.js +310 -0
- package/dist/src/formats/xgmml/styles.js.map +1 -0
- package/dist/src/index.d.ts +9 -7
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +7 -7
- package/dist/src/index.js.map +1 -1
- package/dist/src/positions/codes.d.ts +31 -0
- package/dist/src/positions/codes.d.ts.map +1 -0
- package/dist/src/positions/codes.js +26 -0
- package/dist/src/positions/codes.js.map +1 -0
- package/dist/src/positions/convert.d.ts +58 -0
- package/dist/src/positions/convert.d.ts.map +1 -0
- package/dist/src/positions/convert.js +107 -0
- package/dist/src/positions/convert.js.map +1 -0
- package/dist/src/positions/extract.d.ts +27 -0
- package/dist/src/positions/extract.d.ts.map +1 -0
- package/dist/src/positions/extract.js +526 -0
- package/dist/src/positions/extract.js.map +1 -0
- package/dist/src/positions/index.d.ts +10 -0
- package/dist/src/positions/index.d.ts.map +1 -0
- package/dist/src/positions/index.js +9 -0
- package/dist/src/positions/index.js.map +1 -0
- package/dist/src/positions/types.d.ts +208 -0
- package/dist/src/positions/types.d.ts.map +1 -0
- package/dist/src/positions/types.js +10 -0
- package/dist/src/positions/types.js.map +1 -0
- package/dist/src/registry.d.ts +30 -0
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +130 -9
- package/dist/src/registry.js.map +1 -1
- package/dist/src/styles/annotations.d.ts +132 -0
- package/dist/src/styles/annotations.d.ts.map +1 -0
- package/dist/src/styles/annotations.js +320 -0
- package/dist/src/styles/annotations.js.map +1 -0
- package/dist/src/styles/budget.d.ts +45 -0
- package/dist/src/styles/budget.d.ts.map +1 -0
- package/dist/src/styles/budget.js +58 -0
- package/dist/src/styles/budget.js.map +1 -0
- package/dist/src/styles/canon/bends.d.ts +32 -0
- package/dist/src/styles/canon/bends.d.ts.map +1 -0
- package/dist/src/styles/canon/bends.js +74 -0
- package/dist/src/styles/canon/bends.js.map +1 -0
- package/dist/src/styles/canon/color-tables.d.ts +22 -0
- package/dist/src/styles/canon/color-tables.d.ts.map +1 -0
- package/dist/src/styles/canon/color-tables.js +369 -0
- package/dist/src/styles/canon/color-tables.js.map +1 -0
- package/dist/src/styles/canon/color.d.ts +66 -0
- package/dist/src/styles/canon/color.d.ts.map +1 -0
- package/dist/src/styles/canon/color.js +548 -0
- package/dist/src/styles/canon/color.js.map +1 -0
- package/dist/src/styles/canon/enums.d.ts +25 -0
- package/dist/src/styles/canon/enums.d.ts.map +1 -0
- package/dist/src/styles/canon/enums.js +187 -0
- package/dist/src/styles/canon/enums.js.map +1 -0
- package/dist/src/styles/canon/graphviz.d.ts +48 -0
- package/dist/src/styles/canon/graphviz.d.ts.map +1 -0
- package/dist/src/styles/canon/graphviz.js +160 -0
- package/dist/src/styles/canon/graphviz.js.map +1 -0
- package/dist/src/styles/canon/index.d.ts +13 -0
- package/dist/src/styles/canon/index.d.ts.map +1 -0
- package/dist/src/styles/canon/index.js +13 -0
- package/dist/src/styles/canon/index.js.map +1 -0
- package/dist/src/styles/canon/number.d.ts +59 -0
- package/dist/src/styles/canon/number.d.ts.map +1 -0
- package/dist/src/styles/canon/number.js +142 -0
- package/dist/src/styles/canon/number.js.map +1 -0
- package/dist/src/styles/canon/site.d.ts +51 -0
- package/dist/src/styles/canon/site.d.ts.map +1 -0
- package/dist/src/styles/canon/site.js +63 -0
- package/dist/src/styles/canon/site.js.map +1 -0
- package/dist/src/styles/canon/text.d.ts +61 -0
- package/dist/src/styles/canon/text.d.ts.map +1 -0
- package/dist/src/styles/canon/text.js +199 -0
- package/dist/src/styles/canon/text.js.map +1 -0
- package/dist/src/styles/codes.d.ts +95 -0
- package/dist/src/styles/codes.d.ts.map +1 -0
- package/dist/src/styles/codes.js +97 -0
- package/dist/src/styles/codes.js.map +1 -0
- package/dist/src/styles/cyjs/cascade.d.ts +134 -0
- package/dist/src/styles/cyjs/cascade.d.ts.map +1 -0
- package/dist/src/styles/cyjs/cascade.js +2252 -0
- package/dist/src/styles/cyjs/cascade.js.map +1 -0
- package/dist/src/styles/cyjs/defaults-table.d.ts +25 -0
- package/dist/src/styles/cyjs/defaults-table.d.ts.map +1 -0
- package/dist/src/styles/cyjs/defaults-table.js +76 -0
- package/dist/src/styles/cyjs/defaults-table.js.map +1 -0
- package/dist/src/styles/cyjs/emit.d.ts +82 -0
- package/dist/src/styles/cyjs/emit.d.ts.map +1 -0
- package/dist/src/styles/cyjs/emit.js +790 -0
- package/dist/src/styles/cyjs/emit.js.map +1 -0
- package/dist/src/styles/cyjs/index.d.ts +13 -0
- package/dist/src/styles/cyjs/index.d.ts.map +1 -0
- package/dist/src/styles/cyjs/index.js +13 -0
- package/dist/src/styles/cyjs/index.js.map +1 -0
- package/dist/src/styles/cyjs/live.d.ts +46 -0
- package/dist/src/styles/cyjs/live.d.ts.map +1 -0
- package/dist/src/styles/cyjs/live.js +108 -0
- package/dist/src/styles/cyjs/live.js.map +1 -0
- package/dist/src/styles/cyjs/mappers.d.ts +147 -0
- package/dist/src/styles/cyjs/mappers.d.ts.map +1 -0
- package/dist/src/styles/cyjs/mappers.js +744 -0
- package/dist/src/styles/cyjs/mappers.js.map +1 -0
- package/dist/src/styles/cyjs/selector.d.ts +113 -0
- package/dist/src/styles/cyjs/selector.d.ts.map +1 -0
- package/dist/src/styles/cyjs/selector.js +611 -0
- package/dist/src/styles/cyjs/selector.js.map +1 -0
- package/dist/src/styles/cyjs/stylesheet-text.d.ts +37 -0
- package/dist/src/styles/cyjs/stylesheet-text.d.ts.map +1 -0
- package/dist/src/styles/cyjs/stylesheet-text.js +181 -0
- package/dist/src/styles/cyjs/stylesheet-text.js.map +1 -0
- package/dist/src/styles/cytoscape/emit.d.ts +125 -0
- package/dist/src/styles/cytoscape/emit.d.ts.map +1 -0
- package/dist/src/styles/cytoscape/emit.js +1025 -0
- package/dist/src/styles/cytoscape/emit.js.map +1 -0
- package/dist/src/styles/cytoscape/index.d.ts +10 -0
- package/dist/src/styles/cytoscape/index.d.ts.map +1 -0
- package/dist/src/styles/cytoscape/index.js +10 -0
- package/dist/src/styles/cytoscape/index.js.map +1 -0
- package/dist/src/styles/cytoscape/lexicon.d.ts +49 -0
- package/dist/src/styles/cytoscape/lexicon.d.ts.map +1 -0
- package/dist/src/styles/cytoscape/lexicon.js +603 -0
- package/dist/src/styles/cytoscape/lexicon.js.map +1 -0
- package/dist/src/styles/cytoscape/mappings.d.ts +171 -0
- package/dist/src/styles/cytoscape/mappings.d.ts.map +1 -0
- package/dist/src/styles/cytoscape/mappings.js +460 -0
- package/dist/src/styles/cytoscape/mappings.js.map +1 -0
- package/dist/src/styles/cytoscape/resolve.d.ts +137 -0
- package/dist/src/styles/cytoscape/resolve.d.ts.map +1 -0
- package/dist/src/styles/cytoscape/resolve.js +381 -0
- package/dist/src/styles/cytoscape/resolve.js.map +1 -0
- package/dist/src/styles/cytoscape/translate.d.ts +50 -0
- package/dist/src/styles/cytoscape/translate.d.ts.map +1 -0
- package/dist/src/styles/cytoscape/translate.js +156 -0
- package/dist/src/styles/cytoscape/translate.js.map +1 -0
- package/dist/src/styles/defaults.d.ts +90 -0
- package/dist/src/styles/defaults.d.ts.map +1 -0
- package/dist/src/styles/defaults.js +414 -0
- package/dist/src/styles/defaults.js.map +1 -0
- package/dist/src/styles/index.d.ts +15 -0
- package/dist/src/styles/index.d.ts.map +1 -0
- package/dist/src/styles/index.js +14 -0
- package/dist/src/styles/index.js.map +1 -0
- package/dist/src/styles/internal.d.ts +17 -0
- package/dist/src/styles/internal.d.ts.map +1 -0
- package/dist/src/styles/internal.js +16 -0
- package/dist/src/styles/internal.js.map +1 -0
- package/dist/src/styles/io/approximations.d.ts +24 -0
- package/dist/src/styles/io/approximations.d.ts.map +1 -0
- package/dist/src/styles/io/approximations.js +51 -0
- package/dist/src/styles/io/approximations.js.map +1 -0
- package/dist/src/styles/io/block.d.ts +166 -0
- package/dist/src/styles/io/block.d.ts.map +1 -0
- package/dist/src/styles/io/block.js +930 -0
- package/dist/src/styles/io/block.js.map +1 -0
- package/dist/src/styles/io/generic.d.ts +88 -0
- package/dist/src/styles/io/generic.d.ts.map +1 -0
- package/dist/src/styles/io/generic.js +516 -0
- package/dist/src/styles/io/generic.js.map +1 -0
- package/dist/src/styles/io/index.d.ts +8 -0
- package/dist/src/styles/io/index.d.ts.map +1 -0
- package/dist/src/styles/io/index.js +7 -0
- package/dist/src/styles/io/index.js.map +1 -0
- package/dist/src/styles/io/writer.d.ts +80 -0
- package/dist/src/styles/io/writer.d.ts.map +1 -0
- package/dist/src/styles/io/writer.js +596 -0
- package/dist/src/styles/io/writer.js.map +1 -0
- package/dist/src/styles/notes.d.ts +47 -0
- package/dist/src/styles/notes.d.ts.map +1 -0
- package/dist/src/styles/notes.js +140 -0
- package/dist/src/styles/notes.js.map +1 -0
- package/dist/src/styles/plan/classes.d.ts +31 -0
- package/dist/src/styles/plan/classes.d.ts.map +1 -0
- package/dist/src/styles/plan/classes.js +139 -0
- package/dist/src/styles/plan/classes.js.map +1 -0
- package/dist/src/styles/plan/continuous.d.ts +32 -0
- package/dist/src/styles/plan/continuous.d.ts.map +1 -0
- package/dist/src/styles/plan/continuous.js +165 -0
- package/dist/src/styles/plan/continuous.js.map +1 -0
- package/dist/src/styles/plan/discrete.d.ts +39 -0
- package/dist/src/styles/plan/discrete.d.ts.map +1 -0
- package/dist/src/styles/plan/discrete.js +127 -0
- package/dist/src/styles/plan/discrete.js.map +1 -0
- package/dist/src/styles/plan/families.d.ts +31 -0
- package/dist/src/styles/plan/families.d.ts.map +1 -0
- package/dist/src/styles/plan/families.js +95 -0
- package/dist/src/styles/plan/families.js.map +1 -0
- package/dist/src/styles/plan/features.d.ts +58 -0
- package/dist/src/styles/plan/features.d.ts.map +1 -0
- package/dist/src/styles/plan/features.js +185 -0
- package/dist/src/styles/plan/features.js.map +1 -0
- package/dist/src/styles/plan/index.d.ts +7 -0
- package/dist/src/styles/plan/index.d.ts.map +1 -0
- package/dist/src/styles/plan/index.js +7 -0
- package/dist/src/styles/plan/index.js.map +1 -0
- package/dist/src/styles/plan/plan.d.ts +71 -0
- package/dist/src/styles/plan/plan.d.ts.map +1 -0
- package/dist/src/styles/plan/plan.js +893 -0
- package/dist/src/styles/plan/plan.js.map +1 -0
- package/dist/src/styles/plan/resolve.d.ts +137 -0
- package/dist/src/styles/plan/resolve.d.ts.map +1 -0
- package/dist/src/styles/plan/resolve.js +587 -0
- package/dist/src/styles/plan/resolve.js.map +1 -0
- package/dist/src/styles/types.d.ts +702 -0
- package/dist/src/styles/types.d.ts.map +1 -0
- package/dist/src/styles/types.js +10 -0
- package/dist/src/styles/types.js.map +1 -0
- package/dist/src/styles/vocabulary.d.ts +41 -0
- package/dist/src/styles/vocabulary.d.ts.map +1 -0
- package/dist/src/styles/vocabulary.js +140 -0
- package/dist/src/styles/vocabulary.js.map +1 -0
- package/dist/src/types.d.ts +64 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/styles.d.ts +1 -0
- package/dist/styles.js +322 -0
- package/dist/styles.js.map +1 -0
- package/dist/xgmml.js +5 -4
- package/dist/xgmml.js.map +1 -1
- package/package.json +13 -2
- package/src/common/codes.ts +7 -0
- package/src/common/escape.ts +5 -2
- package/src/common/export.ts +179 -140
- package/src/common/input.ts +8 -4
- package/src/common/json-elements.ts +169 -38
- package/src/common/notes.ts +94 -0
- package/src/common/report.ts +41 -1
- package/src/common/units.ts +42 -0
- package/src/common/xml.ts +45 -5
- package/src/formats/cx/exporter.ts +95 -11
- package/src/formats/cx/importer.ts +126 -90
- package/src/formats/cx/styles.ts +304 -0
- package/src/formats/cx2/exporter.ts +234 -77
- package/src/formats/cx2/importer.ts +19 -1
- package/src/formats/cx2/styles.ts +29 -0
- package/src/formats/cys/constants.ts +3 -0
- package/src/formats/cys/exporter.ts +246 -60
- package/src/formats/cys/importer.ts +125 -9
- package/src/formats/cys/session.ts +6 -0
- package/src/formats/cys/styles.ts +254 -0
- package/src/formats/cys/tables.ts +117 -48
- package/src/formats/dot/exporter.ts +262 -126
- package/src/formats/dot/importer.ts +111 -20
- package/src/formats/dot/index.ts +1 -0
- package/src/formats/dot/positions.ts +77 -0
- package/src/formats/dot/styles.ts +1741 -0
- package/src/formats/gexf/exporter.ts +30 -13
- package/src/formats/gexf/importer.ts +308 -158
- package/src/formats/gexf/index.ts +10 -0
- package/src/formats/gexf/schema.ts +5 -0
- package/src/formats/gexf/styles.ts +719 -0
- package/src/formats/gml/exporter.ts +33 -14
- package/src/formats/gml/importer.ts +4 -0
- package/src/formats/gml/index.ts +2 -1
- package/src/formats/gml/positions.ts +52 -0
- package/src/formats/gml/styles.ts +1248 -0
- package/src/formats/gml/syntax.ts +173 -62
- package/src/formats/graphml/constants.ts +5 -0
- package/src/formats/graphml/exporter.ts +163 -71
- package/src/formats/graphml/importer.ts +119 -45
- package/src/formats/graphml/index.ts +1 -0
- package/src/formats/graphml/styles-plain.ts +236 -0
- package/src/formats/graphml/styles-yed.ts +1221 -0
- package/src/formats/graphml/styles-yfiles3.ts +573 -0
- package/src/formats/graphml/tree.ts +36 -20
- package/src/formats/graphml/yfiles.ts +89 -13
- package/src/formats/json/exporter.ts +76 -26
- package/src/formats/json/importer.ts +543 -323
- package/src/formats/json/positions.ts +50 -0
- package/src/formats/json/styles.ts +2082 -0
- package/src/formats/neo4j/exporter.ts +2 -1
- package/src/formats/pajek/exporter.ts +195 -106
- package/src/formats/pajek/importer.ts +78 -9
- package/src/formats/pajek/index.ts +2 -0
- package/src/formats/pajek/styles.ts +685 -0
- package/src/formats/pajek/syntax.ts +7 -0
- package/src/formats/xgmml/columns.ts +39 -9
- package/src/formats/xgmml/constants.ts +3 -0
- package/src/formats/xgmml/document.ts +54 -12
- package/src/formats/xgmml/emit.ts +11 -6
- package/src/formats/xgmml/exporter.ts +32 -13
- package/src/formats/xgmml/importer.ts +43 -29
- package/src/formats/xgmml/styles.ts +400 -0
- package/src/index.ts +16 -0
- package/src/positions/codes.ts +32 -0
- package/src/positions/convert.ts +123 -0
- package/src/positions/extract.ts +619 -0
- package/src/positions/index.ts +23 -0
- package/src/positions/types.ts +221 -0
- package/src/registry.ts +179 -8
- package/src/styles/annotations.ts +478 -0
- package/src/styles/budget.ts +60 -0
- package/src/styles/canon/bends.ts +84 -0
- package/src/styles/canon/color-tables.ts +386 -0
- package/src/styles/canon/color.ts +624 -0
- package/src/styles/canon/enums.ts +211 -0
- package/src/styles/canon/graphviz.ts +189 -0
- package/src/styles/canon/index.ts +13 -0
- package/src/styles/canon/number.ts +152 -0
- package/src/styles/canon/site.ts +87 -0
- package/src/styles/canon/text.ts +221 -0
- package/src/styles/codes.ts +104 -0
- package/src/styles/cyjs/cascade.ts +2670 -0
- package/src/styles/cyjs/defaults-table.ts +82 -0
- package/src/styles/cyjs/emit.ts +951 -0
- package/src/styles/cyjs/index.ts +37 -0
- package/src/styles/cyjs/live.ts +147 -0
- package/src/styles/cyjs/mappers.ts +879 -0
- package/src/styles/cyjs/selector.ts +778 -0
- package/src/styles/cyjs/stylesheet-text.ts +214 -0
- package/src/styles/cytoscape/emit.ts +1264 -0
- package/src/styles/cytoscape/index.ts +40 -0
- package/src/styles/cytoscape/lexicon.ts +656 -0
- package/src/styles/cytoscape/mappings.ts +603 -0
- package/src/styles/cytoscape/resolve.ts +521 -0
- package/src/styles/cytoscape/translate.ts +237 -0
- package/src/styles/defaults.ts +504 -0
- package/src/styles/index.ts +57 -0
- package/src/styles/internal.ts +17 -0
- package/src/styles/io/approximations.ts +47 -0
- package/src/styles/io/block.ts +1138 -0
- package/src/styles/io/generic.ts +687 -0
- package/src/styles/io/index.ts +18 -0
- package/src/styles/io/writer.ts +745 -0
- package/src/styles/notes.ts +165 -0
- package/src/styles/plan/classes.ts +166 -0
- package/src/styles/plan/continuous.ts +218 -0
- package/src/styles/plan/discrete.ts +165 -0
- package/src/styles/plan/families.ts +115 -0
- package/src/styles/plan/features.ts +234 -0
- package/src/styles/plan/index.ts +7 -0
- package/src/styles/plan/plan.ts +1129 -0
- package/src/styles/plan/resolve.ts +685 -0
- package/src/styles/types.ts +814 -0
- package/src/styles/vocabulary.ts +172 -0
- package/src/types.ts +76 -1
- package/dist/chunks/constants-fT3E8JYY.js.map +0 -1
- package/dist/chunks/escape-B62ZGM_a.js.map +0 -1
- package/dist/chunks/export-rKLeGQMo.js.map +0 -1
- package/dist/chunks/exporter-8hLNemFk.js.map +0 -1
- package/dist/chunks/exporter-BWwEuOPT.js.map +0 -1
- package/dist/chunks/exporter-CpRyHZ3H.js.map +0 -1
- package/dist/chunks/importer-BbNb7eNg.js.map +0 -1
- package/dist/chunks/importer-C98dpSH4.js.map +0 -1
- package/dist/chunks/importer-D794XUTe.js.map +0 -1
- package/dist/chunks/importer-Dz7tI8Sa.js.map +0 -1
- package/dist/chunks/importer-Ht7LNg8L.js.map +0 -1
- package/dist/chunks/importer-WrGRZb0N.js.map +0 -1
- package/dist/chunks/importer-xZ-3suY1.js.map +0 -1
- package/dist/chunks/json-elements-DKSqpNW1.js.map +0 -1
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { GraphFormatError, INVALID_INDEX } from "@graphty/graph-format";
|
|
2
2
|
import { c as childrenCsr } from "./children-CA4coBi0.js";
|
|
3
|
-
import { L as LOSS,
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { L as LOSS, c as capabilities, r as resolveExportOptions, a as checkCapabilities, ai as countMixedEdges, e as explicitWeights, p as pairFolding, G as sanitizeIds, a1 as canonicalId, g as resolveImportOptions, i as reportUnusedOptions, ab as readText, j as reportSinkOptions, h as throwIfAborted, k as graphChosen, I as IdCoercer, l as DirectionResolver, s as parseWeightText, aj as canonicalEncoding, d as declareResolved } from "./export-D7IGzTG4.js";
|
|
4
|
+
import { k as isWritableDotText, m as quoteDotId } from "./escape-B1rMftd9.js";
|
|
5
|
+
import { p as plural, V as agree, $ as formatF32, a0 as formatF64, _ as idText, aO as formatDecimal, ad as formatInteger, M as MIXED_DIRECTION_CODE, D as DIRECTION_FORCED_CODE, a as DIRECTION_REFUSED_CODE, S as SINK_OPTION_CODE, I as ID_MERGED_CODE, O as OPTION_IGNORED_CODE, C as COLUMN_RENAMED_CODE, R as ROLE_TAKEN_CODE, k as DUPLICATE_ATTRIBUTE_CODE, P as PRECISION_CODE, a2 as AMBIGUOUS_GRAPH_NAME_CODE, a3 as GRAPH_NOT_FOUND_CODE, h as MULTIPLE_GRAPHS_CODE, q as ENCODING_CONFLICT_CODE, r as UNKNOWN_ENCODING_CODE, s as ENCODING_FALLBACK_CODE, t as INVALID_ENCODING_CODE, u as INVALID_UTF8_CODE, E as EMPTY_INPUT_CODE, a8 as SYNTAX_CODE, x as ELEMENT_ISSUE, y as INPUT_ISSUE, Z as ImportReportBuilder } from "./format-GDmO6m6Q.js";
|
|
6
|
+
import { i as inferTextDtype, W as WIDENING_UNSUPPORTED_CODE, p as parseTextCell, T as TextCellWriter } from "./text-CgzMqHQb.js";
|
|
6
7
|
import { j as joinText, e as encodeChunks, i as indentUnit } from "./writer-DxjgHwSe.js";
|
|
7
|
-
import { i as importChosenGraph } from "./choose-
|
|
8
|
+
import { i as importChosenGraph } from "./choose-BemygfH8.js";
|
|
9
|
+
import { m as median } from "./convert-BcQ8_jMo.js";
|
|
10
|
+
import { x as writeStyleBlock, S as STYLE_BLOCK_NAME, y as styleBlockLosses, j as StyleNotes, n as noteAt, a as STYLE_ISSUE, z as htmlLabelText, A as dotLabelText, m as plainCell, c as canonColor, o as colorOpacity, p as parseStyleBlock, k as styleFingerprint, l as blockStyles, M as MAX_STYLE_VALUE_LENGTH, b as canonNumber, f as canonEnum, B as recordLabelText, d as num6, r as resolveStyles, C as DOT_POINTS_PER_INCH, w as toolDefaults } from "./block-JQiwViEt.js";
|
|
11
|
+
import { S as StyleApproximations } from "./approximations-3Q4TsdTh.js";
|
|
12
|
+
import { v as valueColumns } from "./styles-yed-DAfcIkf7.js";
|
|
8
13
|
const DOT_FORMAT = "dot";
|
|
9
14
|
const DOT_ORIGIN = Object.freeze({ format: DOT_FORMAT });
|
|
10
15
|
const CLUSTER_COLUMN = "graphty.cluster";
|
|
@@ -17,6 +22,1038 @@ const POSITION_COLUMN = "graphty.position";
|
|
|
17
22
|
const KEY_ATTRIBUTE = "key";
|
|
18
23
|
const PIN_ATTRIBUTE = "pin";
|
|
19
24
|
const DOT_META_KEY = "dot";
|
|
25
|
+
const DOT_STYLE_CAPABILITIES = Object.freeze({
|
|
26
|
+
node: Object.freeze([
|
|
27
|
+
"fill",
|
|
28
|
+
"fillOpacity",
|
|
29
|
+
"borderColor",
|
|
30
|
+
"borderWidth",
|
|
31
|
+
"borderStyle",
|
|
32
|
+
"shape",
|
|
33
|
+
"width",
|
|
34
|
+
"height",
|
|
35
|
+
"label",
|
|
36
|
+
"labelColor",
|
|
37
|
+
"labelSize",
|
|
38
|
+
"labelFont",
|
|
39
|
+
"tooltip",
|
|
40
|
+
"visible"
|
|
41
|
+
]),
|
|
42
|
+
edge: Object.freeze([
|
|
43
|
+
"color",
|
|
44
|
+
"opacity",
|
|
45
|
+
"width",
|
|
46
|
+
"lineStyle",
|
|
47
|
+
"sourceArrow",
|
|
48
|
+
"targetArrow",
|
|
49
|
+
"arrowSize",
|
|
50
|
+
"label",
|
|
51
|
+
"sourceLabel",
|
|
52
|
+
"targetLabel",
|
|
53
|
+
"labelColor",
|
|
54
|
+
"labelSize",
|
|
55
|
+
"labelFont",
|
|
56
|
+
"tooltip",
|
|
57
|
+
"visible"
|
|
58
|
+
]),
|
|
59
|
+
graph: Object.freeze(["background"]),
|
|
60
|
+
block: "native"
|
|
61
|
+
});
|
|
62
|
+
const NAME_KEY = "name";
|
|
63
|
+
const DIRECTED_KEY = "directed";
|
|
64
|
+
const CLUSTER_KEY = "cluster";
|
|
65
|
+
const NODE_ATTRIBUTES = [
|
|
66
|
+
"colorscheme",
|
|
67
|
+
"color",
|
|
68
|
+
"fillcolor",
|
|
69
|
+
"bgcolor",
|
|
70
|
+
"pencolor",
|
|
71
|
+
"style",
|
|
72
|
+
"shape",
|
|
73
|
+
"width",
|
|
74
|
+
"height",
|
|
75
|
+
"fixedsize",
|
|
76
|
+
"regular",
|
|
77
|
+
"penwidth",
|
|
78
|
+
"fontname",
|
|
79
|
+
"fontsize",
|
|
80
|
+
"fontcolor",
|
|
81
|
+
"tooltip"
|
|
82
|
+
];
|
|
83
|
+
const EDGE_ATTRIBUTES = [
|
|
84
|
+
"colorscheme",
|
|
85
|
+
"color",
|
|
86
|
+
"style",
|
|
87
|
+
"penwidth",
|
|
88
|
+
"fontname",
|
|
89
|
+
"fontsize",
|
|
90
|
+
"fontcolor",
|
|
91
|
+
"tooltip",
|
|
92
|
+
"edgetooltip",
|
|
93
|
+
"arrowhead",
|
|
94
|
+
"arrowtail",
|
|
95
|
+
"dir",
|
|
96
|
+
"arrowsize",
|
|
97
|
+
"headlabel",
|
|
98
|
+
"taillabel"
|
|
99
|
+
];
|
|
100
|
+
const NOTED_ATTRIBUTES = ["peripheries", "xlabel"];
|
|
101
|
+
const CIRCLE_LIKE = /* @__PURE__ */ new Set(["circle", "doublecircle", "mcircle", "square", "msquare"]);
|
|
102
|
+
const BOX_LIKE = /* @__PURE__ */ new Set(["box", "rect", "rectangle", "square"]);
|
|
103
|
+
const ELLIPSE_LIKE = /* @__PURE__ */ new Set(["", "ellipse", "oval", "circle"]);
|
|
104
|
+
const NO_OUTLINE = /* @__PURE__ */ new Set(["plain", "plaintext", "none"]);
|
|
105
|
+
const RECORD = /* @__PURE__ */ new Set(["record", "mrecord"]);
|
|
106
|
+
const TRUE_TEXTS$1 = /* @__PURE__ */ new Set(["true", "yes", "shape"]);
|
|
107
|
+
const POINT_SIZE = 0.05;
|
|
108
|
+
const REGULAR_SIZE = 0.5;
|
|
109
|
+
function isHtmlString(text) {
|
|
110
|
+
if (text.length < 2 || !text.startsWith("<") || !text.endsWith(">")) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
let depth = 0;
|
|
114
|
+
for (let i = 0; i < text.length; i++) {
|
|
115
|
+
const c = text.codePointAt(i);
|
|
116
|
+
if (c === 60) {
|
|
117
|
+
depth++;
|
|
118
|
+
} else if (c === 62) {
|
|
119
|
+
depth--;
|
|
120
|
+
if (depth === 0 && i !== text.length - 1) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return depth === 0;
|
|
126
|
+
}
|
|
127
|
+
function cellText$1(table, name, i) {
|
|
128
|
+
if (!table.has(name)) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
const v = plainCell(table.value(name, i));
|
|
132
|
+
if (typeof v === "string") {
|
|
133
|
+
return v;
|
|
134
|
+
}
|
|
135
|
+
return typeof v === "number" || typeof v === "boolean" ? String(v) : null;
|
|
136
|
+
}
|
|
137
|
+
function nonEmpty(v) {
|
|
138
|
+
return v === null || v === "" ? null : v;
|
|
139
|
+
}
|
|
140
|
+
function styleTokens(raw, at) {
|
|
141
|
+
if (raw === null) {
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
if (raw.length > MAX_STYLE_VALUE_LENGTH) {
|
|
145
|
+
noteAt(at, STYLE_ISSUE.VALUE_TOO_LONG, `${String(raw.length)} characters`);
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
return raw.toLowerCase().split(",").map((t) => t.replace(/^[ \t\r\n]+/, "")).filter((t) => t !== "");
|
|
149
|
+
}
|
|
150
|
+
function setLineWidth(tokens) {
|
|
151
|
+
for (const t of tokens) {
|
|
152
|
+
if (t.startsWith("setlinewidth(") && t.endsWith(")")) {
|
|
153
|
+
return t.slice("setlinewidth(".length, -1).trim();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
function isTrue(raw) {
|
|
159
|
+
if (raw === null) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
const t = raw.trim().toLowerCase();
|
|
163
|
+
return TRUE_TEXTS$1.has(t) || /^-?\d+$/.test(t) && Number(t) !== 0;
|
|
164
|
+
}
|
|
165
|
+
function labelText(raw, names, html, record, at) {
|
|
166
|
+
if (isHtmlString(raw)) {
|
|
167
|
+
return htmlLabelText(raw, at);
|
|
168
|
+
}
|
|
169
|
+
if (html.has(`<${raw}>`)) {
|
|
170
|
+
return htmlLabelText(`<${raw}>`, at);
|
|
171
|
+
}
|
|
172
|
+
return dotLabelText(record ? recordLabelText(raw, at) : raw, names, at);
|
|
173
|
+
}
|
|
174
|
+
function readColor(raw, scheme, use, property, opacity, put, at) {
|
|
175
|
+
if (raw === null) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
const c = canonColor(raw, "graphviz", at(property), { scheme, use });
|
|
179
|
+
if (c === null) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
put(property, c.color);
|
|
183
|
+
if (opacity !== null) {
|
|
184
|
+
put(opacity, c.alpha);
|
|
185
|
+
} else if (c.alpha > 0 || property !== "borderColor") {
|
|
186
|
+
colorOpacity(c, null, at(property), false);
|
|
187
|
+
}
|
|
188
|
+
return c.alpha;
|
|
189
|
+
}
|
|
190
|
+
function inchesOf(points) {
|
|
191
|
+
const want = num6(points);
|
|
192
|
+
for (let digits = 6; digits < 17; digits++) {
|
|
193
|
+
const inches2 = Number((points / DOT_POINTS_PER_INCH).toPrecision(digits));
|
|
194
|
+
if (num6(inches2 * DOT_POINTS_PER_INCH) === want) {
|
|
195
|
+
return inches2 + 0;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return points / DOT_POINTS_PER_INCH;
|
|
199
|
+
}
|
|
200
|
+
function inches(raw, at) {
|
|
201
|
+
if (raw === null) {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
const v = raw.trim() === "" ? Number.NaN : Number(raw);
|
|
205
|
+
if (!Number.isFinite(v) || v < 0) {
|
|
206
|
+
noteAt(at, STYLE_ISSUE.BAD_VALUE, raw.slice(0, MAX_STYLE_VALUE_LENGTH));
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
return v;
|
|
210
|
+
}
|
|
211
|
+
function readCommon(get, tokens, scheme, names, put, at) {
|
|
212
|
+
if (tokens.includes("invis")) {
|
|
213
|
+
put("visible", false);
|
|
214
|
+
}
|
|
215
|
+
readColor(nonEmpty(get("fontcolor")), scheme, "line", "labelColor", null, put, at);
|
|
216
|
+
const size = get("fontsize");
|
|
217
|
+
put("labelSize", size === null ? null : canonNumber(size, at("labelSize")));
|
|
218
|
+
const font = get("fontname");
|
|
219
|
+
if (font !== null && font.length <= MAX_STYLE_VALUE_LENGTH) {
|
|
220
|
+
put("labelFont", font);
|
|
221
|
+
}
|
|
222
|
+
const tip = get("tooltip") ?? get("edgetooltip");
|
|
223
|
+
if (tip !== null) {
|
|
224
|
+
put("tooltip", dotLabelText(tip, names, at("tooltip")));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function readNode(get, cx, put, at) {
|
|
228
|
+
const tokens = styleTokens(get("style"), at("visible"));
|
|
229
|
+
const shapeRaw = nonEmpty(get("shape"));
|
|
230
|
+
const shape = (shapeRaw ?? "").toLowerCase();
|
|
231
|
+
const n = {
|
|
232
|
+
get,
|
|
233
|
+
cx,
|
|
234
|
+
put,
|
|
235
|
+
at,
|
|
236
|
+
tokens,
|
|
237
|
+
shapeRaw,
|
|
238
|
+
shape,
|
|
239
|
+
point: !cx.cluster && shape === "point",
|
|
240
|
+
scheme: get("colorscheme"),
|
|
241
|
+
color: nonEmpty(get("color"))
|
|
242
|
+
};
|
|
243
|
+
const names = cx.cluster ? { graph: cx.name } : { node: cx.name, graph: cx.graph, edge: "" };
|
|
244
|
+
readCommon(get, tokens, n.scheme, names, put, at);
|
|
245
|
+
if (cx.cluster) {
|
|
246
|
+
readClusterFill(n);
|
|
247
|
+
} else {
|
|
248
|
+
readNodeFill(n);
|
|
249
|
+
}
|
|
250
|
+
readNodeOutline(n);
|
|
251
|
+
readNodeShape(n);
|
|
252
|
+
const label = n.point ? null : get(LABEL_ATTRIBUTE);
|
|
253
|
+
if (label !== null) {
|
|
254
|
+
put("label", labelText(label, names, cx.html, RECORD.has(shape), at("label")));
|
|
255
|
+
}
|
|
256
|
+
if (!cx.cluster) {
|
|
257
|
+
readSize(get, shape, n.point, label ?? (n.point ? null : cx.name), put, at);
|
|
258
|
+
}
|
|
259
|
+
if (Number(get("peripheries")) > 1 || nonEmpty(get("xlabel")) !== null) {
|
|
260
|
+
noteAt(at("label"), STYLE_ISSUE.NOT_CARRIED, nonEmpty(get("xlabel")) === null ? "peripheries" : "xlabel");
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function readClusterFill(n) {
|
|
264
|
+
const { get, tokens } = n;
|
|
265
|
+
const filled = tokens.includes("filled") || tokens.includes("radial") || tokens.includes("striped");
|
|
266
|
+
const bg = nonEmpty(get("bgcolor"));
|
|
267
|
+
const raw = filled ? nonEmpty(get("fillcolor")) ?? n.color ?? bg ?? "lightgrey" : bg;
|
|
268
|
+
readColor(raw, n.scheme, "fill", "fill", "fillOpacity", n.put, n.at);
|
|
269
|
+
}
|
|
270
|
+
function readNodeFill(n) {
|
|
271
|
+
const { shape, point } = n;
|
|
272
|
+
const fillcolor = nonEmpty(n.get("fillcolor"));
|
|
273
|
+
const filled = point || n.tokens.some(
|
|
274
|
+
(t) => t === "filled" || t === "radial" || t === "striped" && BOX_LIKE.has(shape) || t === "wedged" && ELLIPSE_LIKE.has(shape)
|
|
275
|
+
);
|
|
276
|
+
if (filled) {
|
|
277
|
+
const raw = fillcolor ?? n.color ?? (point ? "black" : "lightgrey");
|
|
278
|
+
readColor(raw, n.scheme, "fill", "fill", "fillOpacity", n.put, n.at);
|
|
279
|
+
} else if (fillcolor !== null) {
|
|
280
|
+
noteAt(n.at("fill"), STYLE_ISSUE.UNFILLED, fillcolor.slice(0, MAX_STYLE_VALUE_LENGTH));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function readNodeOutline(n) {
|
|
284
|
+
const { get, cx, put, at, tokens } = n;
|
|
285
|
+
if (!cx.cluster && NO_OUTLINE.has(n.shape)) {
|
|
286
|
+
put("borderWidth", 0);
|
|
287
|
+
} else {
|
|
288
|
+
const outline = cx.cluster ? nonEmpty(get("pencolor")) ?? n.color : n.color;
|
|
289
|
+
const alpha = readColor(outline, n.scheme, "line", "borderColor", null, put, at);
|
|
290
|
+
const width = nonEmpty(get("penwidth")) ?? setLineWidth(tokens);
|
|
291
|
+
if (alpha === 0) {
|
|
292
|
+
put("borderWidth", 0);
|
|
293
|
+
} else if (width !== null) {
|
|
294
|
+
put("borderWidth", penWidth(width, get("penwidth") !== null, at("borderWidth")));
|
|
295
|
+
} else if (tokens.includes("bold")) {
|
|
296
|
+
put("borderWidth", 2);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (tokens.includes("dashed")) {
|
|
300
|
+
put("borderStyle", "dashed");
|
|
301
|
+
} else if (tokens.includes("dotted")) {
|
|
302
|
+
put("borderStyle", "dotted");
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
function readNodeShape(n) {
|
|
306
|
+
const rounded = n.tokens.includes("rounded");
|
|
307
|
+
if (n.cx.cluster) {
|
|
308
|
+
n.put("shape", rounded ? "round-rectangle" : "rectangle");
|
|
309
|
+
} else if (n.shapeRaw !== null) {
|
|
310
|
+
n.put(
|
|
311
|
+
"shape",
|
|
312
|
+
rounded && BOX_LIKE.has(n.shape) ? "round-rectangle" : canonEnum("shape", n.shapeRaw, "graphviz", n.at("shape"))
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
function penWidth(raw, attribute, site) {
|
|
317
|
+
const value = Number(raw.trim());
|
|
318
|
+
if (attribute && Number.isFinite(value) && value < 0) {
|
|
319
|
+
noteAt(site, STYLE_ISSUE.BAD_VALUE, raw.slice(0, MAX_STYLE_VALUE_LENGTH));
|
|
320
|
+
return 0;
|
|
321
|
+
}
|
|
322
|
+
return canonNumber(raw, site);
|
|
323
|
+
}
|
|
324
|
+
function readSize(get, shape, point, label, put, at) {
|
|
325
|
+
let w = inches(get("width"), at("width"));
|
|
326
|
+
let h = inches(get("height"), at("height"));
|
|
327
|
+
const same = point || CIRCLE_LIKE.has(shape) || isTrue(get("regular"));
|
|
328
|
+
if (shape === "plain") {
|
|
329
|
+
w = h = 0;
|
|
330
|
+
} else if (w === null && h === null) {
|
|
331
|
+
if (point) {
|
|
332
|
+
put("width", num6(POINT_SIZE * DOT_POINTS_PER_INCH));
|
|
333
|
+
put("height", num6(POINT_SIZE * DOT_POINTS_PER_INCH));
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (!same) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
w = h = REGULAR_SIZE;
|
|
340
|
+
}
|
|
341
|
+
let ww = w;
|
|
342
|
+
let hh = h;
|
|
343
|
+
if (point) {
|
|
344
|
+
ww = hh = Math.min(w ?? Infinity, h ?? Infinity);
|
|
345
|
+
} else if (same) {
|
|
346
|
+
ww = hh = Math.max(w ?? 0, h ?? 0);
|
|
347
|
+
}
|
|
348
|
+
const exact = point || isTrue(get("fixedsize")) || label === "" && !RECORD.has(shape);
|
|
349
|
+
if (!exact) {
|
|
350
|
+
noteAt(at("width"), STYLE_ISSUE.SIZE_MINIMUM, "grows to fit its label");
|
|
351
|
+
}
|
|
352
|
+
put("width", ww === null ? null : canonNumber(ww, at("width"), DOT_POINTS_PER_INCH));
|
|
353
|
+
put("height", hh === null ? null : canonNumber(hh, at("height"), DOT_POINTS_PER_INCH));
|
|
354
|
+
}
|
|
355
|
+
function readEdge(get, cx, put, at) {
|
|
356
|
+
const tokens = styleTokens(get("style"), at("visible"));
|
|
357
|
+
const scheme = get("colorscheme");
|
|
358
|
+
readCommon(get, tokens, scheme, cx.names, put, at);
|
|
359
|
+
readColor(nonEmpty(get("color")), scheme, "edge", "color", "opacity", put, at);
|
|
360
|
+
readEdgeLine(get, tokens, put, at);
|
|
361
|
+
readEdgeArrows(get, cx, put, at);
|
|
362
|
+
for (const [attribute, property] of [
|
|
363
|
+
[LABEL_ATTRIBUTE, "label"],
|
|
364
|
+
["headlabel", "targetLabel"],
|
|
365
|
+
["taillabel", "sourceLabel"]
|
|
366
|
+
]) {
|
|
367
|
+
const raw = get(attribute);
|
|
368
|
+
if (raw !== null) {
|
|
369
|
+
put(property, labelText(raw, cx.names, cx.html, false, at(property)));
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
if (nonEmpty(get("xlabel")) !== null) {
|
|
373
|
+
noteAt(at("label"), STYLE_ISSUE.NOT_CARRIED, "xlabel");
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
function readEdgeLine(get, tokens, put, at) {
|
|
377
|
+
const width = nonEmpty(get("penwidth")) ?? setLineWidth(tokens);
|
|
378
|
+
if (width !== null) {
|
|
379
|
+
put("width", penWidth(width, get("penwidth") !== null, at("width")));
|
|
380
|
+
} else if (tokens.includes("bold")) {
|
|
381
|
+
put("width", 2);
|
|
382
|
+
}
|
|
383
|
+
if (tokens.includes("dashed")) {
|
|
384
|
+
put("lineStyle", "dashed");
|
|
385
|
+
} else if (tokens.includes("dotted")) {
|
|
386
|
+
put("lineStyle", "dotted");
|
|
387
|
+
} else if (tokens.includes("solid") || tokens.includes("bold")) {
|
|
388
|
+
put("lineStyle", "solid");
|
|
389
|
+
} else if (tokens.includes("tapered")) {
|
|
390
|
+
put("lineStyle", "other:tapered");
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function readEdgeArrows(get, cx, put, at) {
|
|
394
|
+
const dirRaw = nonEmpty(get("dir"));
|
|
395
|
+
const head = nonEmpty(get("arrowhead"));
|
|
396
|
+
const tail = nonEmpty(get("arrowtail"));
|
|
397
|
+
if (dirRaw !== null || head !== null || tail !== null) {
|
|
398
|
+
const dir = (dirRaw ?? (cx.directed ? "forward" : "none")).trim().toLowerCase();
|
|
399
|
+
const forward = dir === "forward" || dir === "both";
|
|
400
|
+
const back = dir === "back" || dir === "both";
|
|
401
|
+
put("targetArrow", forward ? canonEnum("arrow", head ?? "normal", "graphviz", at("targetArrow")) : "none");
|
|
402
|
+
put("sourceArrow", back ? canonEnum("arrow", tail ?? "normal", "graphviz", at("sourceArrow")) : "none");
|
|
403
|
+
}
|
|
404
|
+
const size = get("arrowsize");
|
|
405
|
+
if (size !== null) {
|
|
406
|
+
put("arrowSize", canonNumber(size, at("arrowSize")));
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
function htmlStrings(snapshot) {
|
|
410
|
+
const out = /* @__PURE__ */ new Set();
|
|
411
|
+
for (let i = 0; i < snapshot.nodeCount; i++) {
|
|
412
|
+
const id = snapshot.ids.idOf(i);
|
|
413
|
+
if (typeof id === "string" && isHtmlString(id)) {
|
|
414
|
+
out.add(id);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
for (const [table, n] of [
|
|
418
|
+
[snapshot.nodes, snapshot.nodeCount],
|
|
419
|
+
[snapshot.edges, snapshot.edgeCount]
|
|
420
|
+
]) {
|
|
421
|
+
for (const name of [LABEL_ATTRIBUTE, "headlabel", "taillabel"].filter((c) => table.has(c))) {
|
|
422
|
+
addHtmlCells(table, name, n, out);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return out;
|
|
426
|
+
}
|
|
427
|
+
function addHtmlCells(table, name, n, out) {
|
|
428
|
+
for (let i = 0; i < n; i++) {
|
|
429
|
+
const v = cellText$1(table, name, i);
|
|
430
|
+
if (v !== null && isHtmlString(v)) {
|
|
431
|
+
out.add(v);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function directedEdges(snapshot) {
|
|
436
|
+
const out = new Array(snapshot.edgeCount).fill(snapshot.directed);
|
|
437
|
+
const col = snapshot.directed ? snapshot.edges.byRole("directed") : null;
|
|
438
|
+
if (col !== null) {
|
|
439
|
+
for (let e = 0; e < snapshot.edgeCount; e++) {
|
|
440
|
+
const v = plainCell(col.value(e));
|
|
441
|
+
if (typeof v === "boolean") {
|
|
442
|
+
out[e] = v;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return out;
|
|
447
|
+
}
|
|
448
|
+
function isCluster(snapshot, i) {
|
|
449
|
+
return snapshot.nodes.has(CLUSTER_COLUMN) && snapshot.nodes.value(CLUSTER_COLUMN, i) === true;
|
|
450
|
+
}
|
|
451
|
+
function contexts(snapshot, written = null) {
|
|
452
|
+
const html = htmlStrings(snapshot);
|
|
453
|
+
const graph = snapshot.meta.name ?? "";
|
|
454
|
+
const own = directedEdges(snapshot);
|
|
455
|
+
const directed = written === null || own.every((d) => d === snapshot.directed) ? own : own.map(() => written);
|
|
456
|
+
const name = (i) => String(snapshot.ids.idOf(i));
|
|
457
|
+
return {
|
|
458
|
+
node: (i) => ({ name: name(i), graph, cluster: isCluster(snapshot, i), html }),
|
|
459
|
+
edge: (e) => {
|
|
460
|
+
const tail = name(snapshot.edgeSource(e));
|
|
461
|
+
const head = name(snapshot.edgeTarget(e));
|
|
462
|
+
return {
|
|
463
|
+
names: { graph, tail, head, edge: `${tail}${directed[e] ? "->" : "--"}${head}` },
|
|
464
|
+
directed: directed[e],
|
|
465
|
+
html
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
function defaultLabel(cx, shape, notes) {
|
|
471
|
+
if (cx.cluster || shape === "point") {
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
474
|
+
const at = { notes, target: "node", property: "label" };
|
|
475
|
+
return isHtmlString(cx.name) ? htmlLabelText(cx.name, at) : dotLabelText(String.raw`\N`, { node: cx.name, graph: cx.graph }, at);
|
|
476
|
+
}
|
|
477
|
+
function styleColumns(table, attributes) {
|
|
478
|
+
const own = /* @__PURE__ */ new Set([...attributes, ...NOTED_ATTRIBUTES]);
|
|
479
|
+
return [...table.names()].filter((c) => own.has(c) || c.startsWith("graphty.style."));
|
|
480
|
+
}
|
|
481
|
+
function dotStyles(snapshot, context) {
|
|
482
|
+
const notes = new StyleNotes();
|
|
483
|
+
const cx = contexts(snapshot);
|
|
484
|
+
const node = valueColumns(snapshot.nodeCount);
|
|
485
|
+
const nameColumn = new Array(snapshot.nodeCount).fill(null);
|
|
486
|
+
const clusterColumn = new Array(snapshot.nodeCount).fill(null);
|
|
487
|
+
let named = 0;
|
|
488
|
+
let clusters = 0;
|
|
489
|
+
for (let i = 0; i < snapshot.nodeCount; i++) {
|
|
490
|
+
context.budget.spend("node", NODE_ATTRIBUTES.length);
|
|
491
|
+
const get = (name) => cellText$1(snapshot.nodes, name, i);
|
|
492
|
+
const ncx = cx.node(i);
|
|
493
|
+
const at = (property) => ({ notes, target: "node", property, element: i, budget: context.budget });
|
|
494
|
+
readNode(
|
|
495
|
+
get,
|
|
496
|
+
ncx,
|
|
497
|
+
(p, v) => {
|
|
498
|
+
node.put(i, p, v);
|
|
499
|
+
},
|
|
500
|
+
at
|
|
501
|
+
);
|
|
502
|
+
const shown = defaultLabel(ncx, (get("shape") ?? "").toLowerCase(), notes);
|
|
503
|
+
if (shown !== null) {
|
|
504
|
+
nameColumn[i] = shown;
|
|
505
|
+
named++;
|
|
506
|
+
}
|
|
507
|
+
if (ncx.cluster) {
|
|
508
|
+
clusterColumn[i] = true;
|
|
509
|
+
clusters++;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
const edge = valueColumns(snapshot.edgeCount);
|
|
513
|
+
for (let e = 0; e < snapshot.edgeCount; e++) {
|
|
514
|
+
context.budget.spend("edge", EDGE_ATTRIBUTES.length);
|
|
515
|
+
const get = (name) => cellText$1(snapshot.edges, name, e);
|
|
516
|
+
const at = (property) => ({ notes, target: "edge", property, element: e, budget: context.budget });
|
|
517
|
+
readEdge(
|
|
518
|
+
get,
|
|
519
|
+
cx.edge(e),
|
|
520
|
+
(p, v) => {
|
|
521
|
+
edge.put(e, p, v);
|
|
522
|
+
},
|
|
523
|
+
at
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
const graph = {};
|
|
527
|
+
const bg = nonEmpty(cellText$1(snapshot.graph, "bgcolor", 0));
|
|
528
|
+
if (snapshot.graph.has("bgcolor") && bg !== null) {
|
|
529
|
+
readColor(
|
|
530
|
+
bg,
|
|
531
|
+
cellText$1(snapshot.graph, "colorscheme", 0),
|
|
532
|
+
"fill",
|
|
533
|
+
"background",
|
|
534
|
+
null,
|
|
535
|
+
(p, v) => {
|
|
536
|
+
if (v !== null) {
|
|
537
|
+
graph[p] = v;
|
|
538
|
+
}
|
|
539
|
+
},
|
|
540
|
+
(property) => ({ notes, target: "graph", property })
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
const blockText = cellText$1(snapshot.graph, STYLE_BLOCK_NAME, 0);
|
|
544
|
+
if (blockText !== null) {
|
|
545
|
+
exactFromBlock(snapshot, blockText, { node: node.values, edge: edge.values }, cx);
|
|
546
|
+
}
|
|
547
|
+
const nodeRules = [];
|
|
548
|
+
const nodeColumns = /* @__PURE__ */ new Map();
|
|
549
|
+
if (named > 0) {
|
|
550
|
+
nodeColumns.set(NAME_KEY, nameColumn);
|
|
551
|
+
nodeRules.push({
|
|
552
|
+
id: "node.tool.name-label",
|
|
553
|
+
target: "node",
|
|
554
|
+
role: "passthrough",
|
|
555
|
+
origin: "tool",
|
|
556
|
+
where: { has: { style: NAME_KEY } },
|
|
557
|
+
map: { label: { kind: "passthrough", by: { style: NAME_KEY } } },
|
|
558
|
+
facts: { elements: named, reason: "NODE_NAME" }
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
const features = clusters > 0 ? [{ ref: { style: CLUSTER_KEY }, values: clusterColumn }] : [];
|
|
562
|
+
const edgeRules = [];
|
|
563
|
+
const edgeColumns = /* @__PURE__ */ new Map();
|
|
564
|
+
const directed = directedEdges(snapshot);
|
|
565
|
+
if (directed.some(Boolean)) {
|
|
566
|
+
edgeColumns.set(
|
|
567
|
+
DIRECTED_KEY,
|
|
568
|
+
directed.map((d) => d ? true : null)
|
|
569
|
+
);
|
|
570
|
+
edgeRules.push({
|
|
571
|
+
id: "edge.tool.arrow",
|
|
572
|
+
target: "edge",
|
|
573
|
+
role: "group",
|
|
574
|
+
origin: "tool",
|
|
575
|
+
where: { has: { style: DIRECTED_KEY } },
|
|
576
|
+
set: { targetArrow: "triangle" }
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
return {
|
|
580
|
+
canonical: true,
|
|
581
|
+
dialect: "graphviz",
|
|
582
|
+
tool: "graphviz",
|
|
583
|
+
units: "px",
|
|
584
|
+
node: { values: node.values, rules: nodeRules, columns: nodeColumns, features },
|
|
585
|
+
edge: { values: edge.values, rules: edgeRules, columns: edgeColumns },
|
|
586
|
+
graph,
|
|
587
|
+
notes: notes.list(),
|
|
588
|
+
readFrom: {
|
|
589
|
+
node: styleColumns(snapshot.nodes, NODE_ATTRIBUTES),
|
|
590
|
+
edge: styleColumns(snapshot.edges, EDGE_ATTRIBUTES)
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
const SHAPES = /* @__PURE__ */ new Map([
|
|
595
|
+
["ellipse", "ellipse"],
|
|
596
|
+
["rectangle", "box"],
|
|
597
|
+
["round-rectangle", "box"],
|
|
598
|
+
["triangle", "triangle"],
|
|
599
|
+
["diamond", "diamond"],
|
|
600
|
+
["pentagon", "pentagon"],
|
|
601
|
+
["hexagon", "hexagon"],
|
|
602
|
+
["octagon", "octagon"],
|
|
603
|
+
["parallelogram", "parallelogram"],
|
|
604
|
+
["trapezoid", "trapezium"],
|
|
605
|
+
["star", "star"],
|
|
606
|
+
["none", "none"]
|
|
607
|
+
]);
|
|
608
|
+
const ARROWS = /* @__PURE__ */ new Map([
|
|
609
|
+
["none", "none"],
|
|
610
|
+
["triangle", "normal"],
|
|
611
|
+
["triangle-open", "onormal"],
|
|
612
|
+
["vee", "vee"],
|
|
613
|
+
["tee", "tee"],
|
|
614
|
+
["diamond", "diamond"],
|
|
615
|
+
["diamond-open", "odiamond"],
|
|
616
|
+
["circle", "dot"],
|
|
617
|
+
["circle-open", "odot"],
|
|
618
|
+
["square", "box"],
|
|
619
|
+
["crow", "crow"],
|
|
620
|
+
["half", "lnormal"],
|
|
621
|
+
["inverted", "inv"]
|
|
622
|
+
]);
|
|
623
|
+
const STROKES = /* @__PURE__ */ new Map([
|
|
624
|
+
["dashed", "dashed"],
|
|
625
|
+
["dotted", "dotted"]
|
|
626
|
+
]);
|
|
627
|
+
function graphvizDefaults(target) {
|
|
628
|
+
const t = toolDefaults("graphviz")?.[target];
|
|
629
|
+
const out = /* @__PURE__ */ new Map();
|
|
630
|
+
const add = (attribute, property, scale = 1) => {
|
|
631
|
+
const v = t[property]?.value;
|
|
632
|
+
if (typeof v === "number") {
|
|
633
|
+
out.set(attribute, num6(v / scale));
|
|
634
|
+
} else if (typeof v === "string") {
|
|
635
|
+
out.set(attribute, v);
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
add("fontcolor", "labelColor");
|
|
639
|
+
add("fontsize", "labelSize");
|
|
640
|
+
add("fontname", "labelFont");
|
|
641
|
+
if (target === "node") {
|
|
642
|
+
add("color", "borderColor");
|
|
643
|
+
add("pencolor", "borderColor");
|
|
644
|
+
add("penwidth", "borderWidth");
|
|
645
|
+
add("shape", "shape");
|
|
646
|
+
add("width", "width", DOT_POINTS_PER_INCH);
|
|
647
|
+
add("height", "height", DOT_POINTS_PER_INCH);
|
|
648
|
+
} else {
|
|
649
|
+
add("color", "color");
|
|
650
|
+
add("penwidth", "width");
|
|
651
|
+
add("arrowsize", "arrowSize");
|
|
652
|
+
}
|
|
653
|
+
return out;
|
|
654
|
+
}
|
|
655
|
+
const DEFAULT_ATTRIBUTES = {
|
|
656
|
+
node: graphvizDefaults("node"),
|
|
657
|
+
edge: graphvizDefaults("edge")
|
|
658
|
+
};
|
|
659
|
+
function withoutDefaults(out, target) {
|
|
660
|
+
for (const [attribute, value] of DEFAULT_ATTRIBUTES[target]) {
|
|
661
|
+
if (out.get(attribute) === value) {
|
|
662
|
+
out.delete(attribute);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
if (!out.has("width") && !out.has("height")) {
|
|
666
|
+
out.delete("fixedsize");
|
|
667
|
+
}
|
|
668
|
+
return out;
|
|
669
|
+
}
|
|
670
|
+
function gvColor(color, opacity) {
|
|
671
|
+
if (typeof opacity !== "number" || opacity >= 1) {
|
|
672
|
+
return color;
|
|
673
|
+
}
|
|
674
|
+
const a = Math.max(0, Math.min(255, Math.round(opacity * 255)));
|
|
675
|
+
return color + a.toString(16).padStart(2, "0");
|
|
676
|
+
}
|
|
677
|
+
function escapeLabel(text) {
|
|
678
|
+
return text.replaceAll("\\", String.raw`\\`).replaceAll("\n", String.raw`\n`);
|
|
679
|
+
}
|
|
680
|
+
function spelled(table, value, nearest, property, approximate) {
|
|
681
|
+
const exact = table.get(value);
|
|
682
|
+
if (exact !== void 0) {
|
|
683
|
+
return exact;
|
|
684
|
+
}
|
|
685
|
+
if (value.startsWith("other:")) {
|
|
686
|
+
return value.slice("other:".length);
|
|
687
|
+
}
|
|
688
|
+
approximate(property, value);
|
|
689
|
+
return nearest;
|
|
690
|
+
}
|
|
691
|
+
function writeCommon(get, out, tokens) {
|
|
692
|
+
const color = get("labelColor");
|
|
693
|
+
if (typeof color === "string") {
|
|
694
|
+
out.set("fontcolor", color);
|
|
695
|
+
}
|
|
696
|
+
const size = get("labelSize");
|
|
697
|
+
if (typeof size === "number") {
|
|
698
|
+
out.set("fontsize", size);
|
|
699
|
+
}
|
|
700
|
+
const font = get("labelFont");
|
|
701
|
+
if (typeof font === "string") {
|
|
702
|
+
out.set("fontname", font);
|
|
703
|
+
}
|
|
704
|
+
const tip = get("tooltip");
|
|
705
|
+
if (typeof tip === "string") {
|
|
706
|
+
out.set("tooltip", escapeLabel(tip));
|
|
707
|
+
}
|
|
708
|
+
if (get("visible") === false) {
|
|
709
|
+
tokens.push("invis");
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
function nodeAttributes(get, cx, approximate, notes) {
|
|
713
|
+
const out = /* @__PURE__ */ new Map();
|
|
714
|
+
const tokens = [];
|
|
715
|
+
writeCommon(get, out, tokens);
|
|
716
|
+
writeNodeOutline(get, cx, approximate, out, tokens);
|
|
717
|
+
const gvShape = writeNodeShape(get, cx, approximate, out, tokens);
|
|
718
|
+
if (!cx.cluster) {
|
|
719
|
+
writeNodeSize(get, out);
|
|
720
|
+
}
|
|
721
|
+
const label = get("label");
|
|
722
|
+
const shown = defaultLabel(cx, gvShape, notes);
|
|
723
|
+
if (typeof label === "string" && label !== shown) {
|
|
724
|
+
out.set(LABEL_ATTRIBUTE, escapeLabel(label));
|
|
725
|
+
} else if (label === null && shown !== null) {
|
|
726
|
+
out.set(LABEL_ATTRIBUTE, "");
|
|
727
|
+
}
|
|
728
|
+
if (tokens.length > 0) {
|
|
729
|
+
out.set("style", tokens.join(","));
|
|
730
|
+
}
|
|
731
|
+
return withoutDefaults(out, "node");
|
|
732
|
+
}
|
|
733
|
+
function writeNodeOutline(get, cx, approximate, out, tokens) {
|
|
734
|
+
const fill = get("fill");
|
|
735
|
+
const fillOpacity = get("fillOpacity");
|
|
736
|
+
if (typeof fill === "string" && fillOpacity !== 0) {
|
|
737
|
+
tokens.push("filled");
|
|
738
|
+
out.set("fillcolor", gvColor(fill, fillOpacity));
|
|
739
|
+
}
|
|
740
|
+
const border = get("borderColor");
|
|
741
|
+
if (typeof border === "string") {
|
|
742
|
+
out.set(cx.cluster ? "pencolor" : "color", border);
|
|
743
|
+
}
|
|
744
|
+
const borderWidth = get("borderWidth");
|
|
745
|
+
if (typeof borderWidth === "number") {
|
|
746
|
+
out.set("penwidth", borderWidth);
|
|
747
|
+
}
|
|
748
|
+
const borderStyle = get("borderStyle");
|
|
749
|
+
if (typeof borderStyle === "string" && borderStyle !== "solid") {
|
|
750
|
+
const nearest = borderStyle.includes("dash") ? "dashed" : "solid";
|
|
751
|
+
tokens.push(spelled(STROKES, borderStyle, nearest, "borderStyle", approximate));
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
function writeNodeShape(get, cx, approximate, out, tokens) {
|
|
755
|
+
const shape = get("shape");
|
|
756
|
+
if (typeof shape !== "string") {
|
|
757
|
+
return "";
|
|
758
|
+
}
|
|
759
|
+
if (shape === "round-rectangle") {
|
|
760
|
+
tokens.push("rounded");
|
|
761
|
+
}
|
|
762
|
+
if (cx.cluster) {
|
|
763
|
+
if (shape !== "rectangle" && shape !== "round-rectangle") {
|
|
764
|
+
approximate("shape", shape);
|
|
765
|
+
}
|
|
766
|
+
return "";
|
|
767
|
+
}
|
|
768
|
+
const gvShape = spelled(SHAPES, shape, shape === "vee" ? "invtriangle" : "box", "shape", approximate);
|
|
769
|
+
out.set("shape", gvShape);
|
|
770
|
+
return gvShape;
|
|
771
|
+
}
|
|
772
|
+
function writeNodeSize(get, out) {
|
|
773
|
+
const width = get("width");
|
|
774
|
+
const height = get("height");
|
|
775
|
+
if (typeof width === "number" || typeof height === "number") {
|
|
776
|
+
out.set("fixedsize", "true");
|
|
777
|
+
}
|
|
778
|
+
if (typeof width === "number") {
|
|
779
|
+
out.set("width", inchesOf(width));
|
|
780
|
+
}
|
|
781
|
+
if (typeof height === "number") {
|
|
782
|
+
out.set("height", inchesOf(height));
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
function edgeAttributes(get, directed, approximate) {
|
|
786
|
+
const out = /* @__PURE__ */ new Map();
|
|
787
|
+
const tokens = [];
|
|
788
|
+
writeCommon(get, out, tokens);
|
|
789
|
+
const color = get("color");
|
|
790
|
+
if (typeof color === "string") {
|
|
791
|
+
out.set("color", gvColor(color, get("opacity")));
|
|
792
|
+
}
|
|
793
|
+
const width = get("width");
|
|
794
|
+
if (typeof width === "number") {
|
|
795
|
+
out.set("penwidth", width);
|
|
796
|
+
}
|
|
797
|
+
const line = get("lineStyle");
|
|
798
|
+
if (typeof line === "string" && line !== "solid") {
|
|
799
|
+
tokens.push(spelled(STROKES, line, line.includes("dash") ? "dashed" : "solid", "lineStyle", approximate));
|
|
800
|
+
}
|
|
801
|
+
writeEdgeArrows(get, directed, approximate, out);
|
|
802
|
+
const arrowSize = get("arrowSize");
|
|
803
|
+
if (typeof arrowSize === "number") {
|
|
804
|
+
out.set("arrowsize", arrowSize);
|
|
805
|
+
}
|
|
806
|
+
for (const [property, attribute] of [
|
|
807
|
+
["label", LABEL_ATTRIBUTE],
|
|
808
|
+
["targetLabel", "headlabel"],
|
|
809
|
+
["sourceLabel", "taillabel"]
|
|
810
|
+
]) {
|
|
811
|
+
const v = get(property);
|
|
812
|
+
if (typeof v === "string") {
|
|
813
|
+
out.set(attribute, escapeLabel(v));
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
if (tokens.length > 0) {
|
|
817
|
+
out.set("style", tokens.join(","));
|
|
818
|
+
}
|
|
819
|
+
return withoutDefaults(out, "edge");
|
|
820
|
+
}
|
|
821
|
+
function writeEdgeArrows(get, directed, approximate, out) {
|
|
822
|
+
const source = get("sourceArrow");
|
|
823
|
+
const target = get("targetArrow");
|
|
824
|
+
const tail = typeof source === "string" && source !== "none";
|
|
825
|
+
const head = typeof target === "string" && target !== "none";
|
|
826
|
+
const plain = directed ? head && !tail && target === "triangle" : !head && !tail;
|
|
827
|
+
if (plain || source === null && target === null) {
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
let dir = "none";
|
|
831
|
+
if (head && tail) {
|
|
832
|
+
dir = "both";
|
|
833
|
+
} else if (head) {
|
|
834
|
+
dir = "forward";
|
|
835
|
+
} else if (tail) {
|
|
836
|
+
dir = "back";
|
|
837
|
+
}
|
|
838
|
+
out.set("dir", dir);
|
|
839
|
+
if (head) {
|
|
840
|
+
out.set("arrowhead", spelled(ARROWS, target, "normal", "targetArrow", approximate));
|
|
841
|
+
}
|
|
842
|
+
if (tail) {
|
|
843
|
+
out.set("arrowtail", spelled(ARROWS, source, "normal", "sourceArrow", approximate));
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
function getter(picture, target) {
|
|
847
|
+
const columns = /* @__PURE__ */ new Map();
|
|
848
|
+
for (const p of DOT_STYLE_CAPABILITIES[target]) {
|
|
849
|
+
columns.set(p, picture(target, p));
|
|
850
|
+
}
|
|
851
|
+
return (i) => (property) => columns.get(property)?.[i] ?? null;
|
|
852
|
+
}
|
|
853
|
+
function exactFromBlock(snapshot, text, read, cx) {
|
|
854
|
+
const parsed = parseStyleBlock(text, styleFingerprint(snapshot));
|
|
855
|
+
const ex = parsed.ok ? blockStyles(parsed.block, snapshot, "dot") : null;
|
|
856
|
+
if (ex === null) {
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
const notes = new StyleNotes();
|
|
860
|
+
for (const target of ["node", "edge"]) {
|
|
861
|
+
const n = target === "node" ? snapshot.nodeCount : snapshot.edgeCount;
|
|
862
|
+
const get = getter((t, p) => resolveStyles(ex, t, p, snapshot), target);
|
|
863
|
+
const values = read[target];
|
|
864
|
+
for (let i = 0; i < n; i++) {
|
|
865
|
+
const want = get(i);
|
|
866
|
+
const back = writtenAndReadBack(target, i, want, cx, notes);
|
|
867
|
+
for (const property of DOT_STYLE_CAPABILITIES[target]) {
|
|
868
|
+
const native = values[property]?.[i] ?? null;
|
|
869
|
+
const w = want(property);
|
|
870
|
+
if (native !== w && native === (back.get(property) ?? null)) {
|
|
871
|
+
values[property] ??= new Array(n).fill(null);
|
|
872
|
+
values[property][i] = w;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
function writtenAndReadBack(target, i, want, cx, notes) {
|
|
879
|
+
const ignore = () => void 0;
|
|
880
|
+
const back = /* @__PURE__ */ new Map();
|
|
881
|
+
const put = (property, value) => {
|
|
882
|
+
if (value !== null) {
|
|
883
|
+
back.set(property, value);
|
|
884
|
+
}
|
|
885
|
+
};
|
|
886
|
+
const at = (property) => ({ notes, target, property });
|
|
887
|
+
if (target === "node") {
|
|
888
|
+
const ncx = cx.node(i);
|
|
889
|
+
const attrs = nodeAttributes(want, ncx, ignore, notes);
|
|
890
|
+
readNode((name) => textOf(attrs.get(name)), ncx, put, at);
|
|
891
|
+
} else {
|
|
892
|
+
const ecx = cx.edge(i);
|
|
893
|
+
const attrs = edgeAttributes(want, ecx.directed, ignore);
|
|
894
|
+
readEdge((name) => textOf(attrs.get(name)), ecx, put, at);
|
|
895
|
+
}
|
|
896
|
+
return back;
|
|
897
|
+
}
|
|
898
|
+
function textOf(v) {
|
|
899
|
+
return v === void 0 ? null : String(v);
|
|
900
|
+
}
|
|
901
|
+
function readsBack(col) {
|
|
902
|
+
const vals = col.filter((v) => v !== null);
|
|
903
|
+
if (vals.every((v) => typeof v === "number")) {
|
|
904
|
+
return vals.every((v) => Number.isFinite(v));
|
|
905
|
+
}
|
|
906
|
+
if (vals.every((v) => typeof v === "boolean")) {
|
|
907
|
+
return true;
|
|
908
|
+
}
|
|
909
|
+
if (vals.every((v) => typeof v === "string")) {
|
|
910
|
+
return vals.some((v) => inferTextDtype(v) === "string") && vals.every((v) => isWritableDotText(v));
|
|
911
|
+
}
|
|
912
|
+
return false;
|
|
913
|
+
}
|
|
914
|
+
function dotSafeJson(json) {
|
|
915
|
+
return json.replaceAll(/\\(["\\])/g, (_m, c) => c === '"' ? String.raw`\u0022` : String.raw`\u005c`);
|
|
916
|
+
}
|
|
917
|
+
function dotStyledExport(snapshot, input, onMixedDirection) {
|
|
918
|
+
if (input === void 0) {
|
|
919
|
+
return null;
|
|
920
|
+
}
|
|
921
|
+
const approximated = new StyleApproximations();
|
|
922
|
+
const replaced = [];
|
|
923
|
+
const out = snapshot.withColumns();
|
|
924
|
+
const written = onMixedDirection === "directed" || onMixedDirection === "undirected";
|
|
925
|
+
const cx = contexts(snapshot, written ? onMixedDirection === "directed" : null);
|
|
926
|
+
const notes = new StyleNotes();
|
|
927
|
+
for (const target of ["node", "edge"]) {
|
|
928
|
+
const table = target === "node" ? out.nodes : out.edges;
|
|
929
|
+
const read = dataRead(input.rules.styles.rules, target);
|
|
930
|
+
const approximate = (property, value) => {
|
|
931
|
+
approximated.add(target, property, value);
|
|
932
|
+
};
|
|
933
|
+
const columns = attributeColumns(snapshot, input, target, { cx, approximate, notes, read });
|
|
934
|
+
replaced.push(...removeStyleAttributes(table, target, columns, read));
|
|
935
|
+
setAttributeColumns(table, columns);
|
|
936
|
+
}
|
|
937
|
+
const { background } = input.rules.styles.graph;
|
|
938
|
+
if (out.graph.has("bgcolor")) {
|
|
939
|
+
out.graph.remove("bgcolor");
|
|
940
|
+
}
|
|
941
|
+
if (typeof background === "string") {
|
|
942
|
+
out.graph.set("bgcolor", [background], { dtype: "string" });
|
|
943
|
+
}
|
|
944
|
+
const inline = [...input.tags.node.values(), ...input.tags.edge.values()].some((col) => !readsBack(col));
|
|
945
|
+
if (!inline) {
|
|
946
|
+
setTagColumns(out, input);
|
|
947
|
+
}
|
|
948
|
+
const block = inline ? writeStyleBlock(input.rules, { inlineColumns: true, snapshot }) : input.block;
|
|
949
|
+
out.graph.set(STYLE_BLOCK_NAME, [dotSafeJson(block)], { dtype: "string" });
|
|
950
|
+
const losses = approximated.notes("Graphviz");
|
|
951
|
+
if (inline) {
|
|
952
|
+
losses.push(...styleBlockLosses(block, input.rules.styles.rules.length, "size"));
|
|
953
|
+
}
|
|
954
|
+
return { snapshot: out, notes: [...replaced, ...losses] };
|
|
955
|
+
}
|
|
956
|
+
function attributeColumns(snapshot, input, target, w) {
|
|
957
|
+
const n = target === "node" ? snapshot.nodeCount : snapshot.edgeCount;
|
|
958
|
+
const get = getter((t, p) => input.picture(t, p), target);
|
|
959
|
+
const columns = /* @__PURE__ */ new Map();
|
|
960
|
+
for (let i = 0; i < n; i++) {
|
|
961
|
+
const attrs = target === "node" ? nodeAttributes(get(i), w.cx.node(i), w.approximate, w.notes) : edgeAttributes(get(i), w.cx.edge(i).directed, w.approximate);
|
|
962
|
+
if (w.read.has(LABEL_ATTRIBUTE) && attrs.get(LABEL_ATTRIBUTE) === "" && get(i)("label") === null) {
|
|
963
|
+
w.approximate("label", "");
|
|
964
|
+
}
|
|
965
|
+
for (const [name, value] of attrs) {
|
|
966
|
+
let col = columns.get(name);
|
|
967
|
+
if (col === void 0) {
|
|
968
|
+
col = new Array(n).fill(null);
|
|
969
|
+
columns.set(name, col);
|
|
970
|
+
}
|
|
971
|
+
col[i] = value;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
return columns;
|
|
975
|
+
}
|
|
976
|
+
function removeStyleAttributes(table, target, columns, read) {
|
|
977
|
+
const attributes = target === "node" ? NODE_ATTRIBUTES : EDGE_ATTRIBUTES;
|
|
978
|
+
const replaced = [];
|
|
979
|
+
for (const name of table.names()) {
|
|
980
|
+
if (!attributes.includes(name) && name !== LABEL_ATTRIBUTE && !name.startsWith("graphty.style.")) {
|
|
981
|
+
continue;
|
|
982
|
+
}
|
|
983
|
+
const differs = read.has(name) ? replacedRows(table, name, columns.get(name)) : 0;
|
|
984
|
+
if (differs > 0) {
|
|
985
|
+
replaced.push(
|
|
986
|
+
Object.freeze({
|
|
987
|
+
code: DOT_ATTRIBUTE_CLASH_CODE,
|
|
988
|
+
message: `${target} column "${name}" is not written: the ${name} attribute holds what graphty draws (${String(differs)} ${target}${differs === 1 ? "" : "s"} differ)`,
|
|
989
|
+
column: name,
|
|
990
|
+
count: differs
|
|
991
|
+
})
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
table.remove(name);
|
|
995
|
+
}
|
|
996
|
+
return replaced;
|
|
997
|
+
}
|
|
998
|
+
function setAttributeColumns(table, columns) {
|
|
999
|
+
for (const [name, col] of columns) {
|
|
1000
|
+
if (name === LABEL_ATTRIBUTE) {
|
|
1001
|
+
table.set(name, col, { dtype: "string", role: "label" }, { replaceRole: true });
|
|
1002
|
+
} else if (col.every((v) => v === null || typeof v === "number")) {
|
|
1003
|
+
table.set(name, col, { dtype: "f64" });
|
|
1004
|
+
} else {
|
|
1005
|
+
table.set(
|
|
1006
|
+
name,
|
|
1007
|
+
col.map((v) => v === null ? null : String(v)),
|
|
1008
|
+
{ dtype: "string" }
|
|
1009
|
+
);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
function setTagColumns(out, input) {
|
|
1014
|
+
for (const target of ["node", "edge"]) {
|
|
1015
|
+
const table = target === "node" ? out.nodes : out.edges;
|
|
1016
|
+
for (const [name, col] of input.tags[target]) {
|
|
1017
|
+
const kinds = new Set(col.filter((v) => v !== null).map((v) => typeof v));
|
|
1018
|
+
let dtype = "string";
|
|
1019
|
+
if (kinds.has("number")) {
|
|
1020
|
+
dtype = "f64";
|
|
1021
|
+
} else if (kinds.has("boolean")) {
|
|
1022
|
+
dtype = "bool";
|
|
1023
|
+
}
|
|
1024
|
+
table.set(name, col, { dtype });
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
function dataRead(rules, target) {
|
|
1029
|
+
const out = /* @__PURE__ */ new Set();
|
|
1030
|
+
for (const { ext: _ext, ...rule } of rules.filter((r) => r.target === target)) {
|
|
1031
|
+
JSON.stringify(rule, (_k, v) => {
|
|
1032
|
+
if (typeof v === "object" && v !== null && !Array.isArray(v) && Object.keys(v).length === 1) {
|
|
1033
|
+
const { data } = v;
|
|
1034
|
+
if (typeof data === "string") {
|
|
1035
|
+
out.add(data);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
return v;
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
return out;
|
|
1042
|
+
}
|
|
1043
|
+
const DOT_ATTRIBUTE_CLASH_CODE = "W_DOT_ATTRIBUTE_CLASH";
|
|
1044
|
+
function replacedRows(table, name, written) {
|
|
1045
|
+
const column = table.get(name);
|
|
1046
|
+
let n = 0;
|
|
1047
|
+
for (let i = 0; column !== null && i < column.length; i++) {
|
|
1048
|
+
const cell = column.isSet(i) ? plainCell(column.value(i)) : null;
|
|
1049
|
+
const w = written?.[i] ?? null;
|
|
1050
|
+
const text = typeof cell === "string" ? cell : JSON.stringify(cell);
|
|
1051
|
+
if (cell !== null && (w === null || String(w) !== text)) {
|
|
1052
|
+
n++;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
return n;
|
|
1056
|
+
}
|
|
20
1057
|
const DOT_LOSS = Object.freeze({
|
|
21
1058
|
/**
|
|
22
1059
|
* An id, name or text with a backslash before a quote or a line break, or at its end, cannot be written as a DOT
|
|
@@ -31,7 +1068,7 @@ const DOT_LOSS = Object.freeze({
|
|
|
31
1068
|
*/
|
|
32
1069
|
TEXT_INFERRED: LOSS.TEXT_INFERRED,
|
|
33
1070
|
/** A plain column named like an attribute the exporter writes for a role (weight, key, pos) is not written. */
|
|
34
|
-
ATTRIBUTE_CLASH:
|
|
1071
|
+
ATTRIBUTE_CLASH: DOT_ATTRIBUTE_CLASH_CODE,
|
|
35
1072
|
/** A mutual pair is written as two directed edges. */
|
|
36
1073
|
MUTUAL_EXPANDED: LOSS.MUTUAL_EXPANDED,
|
|
37
1074
|
/** A parents (multi-parent) column cannot be written; DOT clusters nest. */
|
|
@@ -48,8 +1085,28 @@ const DOT_LOSS = Object.freeze({
|
|
|
48
1085
|
*/
|
|
49
1086
|
ROLE_ASSUMED: LOSS.ROLE_ASSUMED,
|
|
50
1087
|
/** A parent that is a plain node is written as a node and a cluster of one name; it reads back marked as a cluster. */
|
|
51
|
-
CLUSTER_MARKED: "W_DOT_CLUSTER_MARKED"
|
|
1088
|
+
CLUSTER_MARKED: "W_DOT_CLUSTER_MARKED",
|
|
1089
|
+
/** The file is written in UTF-8, so a graph `charset` naming another encoding is written as `UTF-8`. */
|
|
1090
|
+
CHARSET_REWRITTEN: "W_DOT_CHARSET_REWRITTEN"
|
|
52
1091
|
});
|
|
1092
|
+
const UTF8_CHARSET = /^utf-?8$/i;
|
|
1093
|
+
function charsetNotes(column) {
|
|
1094
|
+
const declared = isCharset(column) && column.isSet(0) ? cellText(column, 0) : null;
|
|
1095
|
+
if (declared === null || UTF8_CHARSET.test(declared)) {
|
|
1096
|
+
return [];
|
|
1097
|
+
}
|
|
1098
|
+
return [
|
|
1099
|
+
Object.freeze({
|
|
1100
|
+
code: DOT_LOSS.CHARSET_REWRITTEN,
|
|
1101
|
+
message: `graph attribute charset ${JSON.stringify(declared)} is written as "UTF-8", the encoding the file is written in`,
|
|
1102
|
+
column: column.meta.name,
|
|
1103
|
+
count: 1
|
|
1104
|
+
})
|
|
1105
|
+
];
|
|
1106
|
+
}
|
|
1107
|
+
function isCharset(column) {
|
|
1108
|
+
return column.meta.name.toLowerCase() === "charset";
|
|
1109
|
+
}
|
|
53
1110
|
const KEPT_ROLES = /* @__PURE__ */ new Set(["label", "id", "sourcePort", "targetPort", "parent"]);
|
|
54
1111
|
const ROLE_NAMES = Object.freeze({
|
|
55
1112
|
label: LABEL_ATTRIBUTE,
|
|
@@ -131,21 +1188,20 @@ const dotExporter = Object.freeze({
|
|
|
131
1188
|
format: DOT_FORMAT,
|
|
132
1189
|
options: Object.freeze(["indent", "name", "strict"]),
|
|
133
1190
|
capabilities: CAPABILITIES,
|
|
1191
|
+
styles: Object.freeze({ capabilities: DOT_STYLE_CAPABILITIES }),
|
|
134
1192
|
/**
|
|
135
|
-
* Pre-flight: every loss the DOT text would incur, without writing anything
|
|
1193
|
+
* Pre-flight: every loss the DOT text would incur, without writing anything; with styles, also the values
|
|
1194
|
+
* written as the nearest ones Graphviz has.
|
|
136
1195
|
* @param snapshot - the snapshot to check
|
|
137
1196
|
* @param options - format-specific and common options
|
|
138
1197
|
* @returns the notes, empty when the export is exact
|
|
139
1198
|
*/
|
|
140
1199
|
check(snapshot, options) {
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
});
|
|
147
|
-
const plan = new ExportPlan(snapshot, resolved, options);
|
|
148
|
-
return [...notes, ...plan.notes()];
|
|
1200
|
+
const styled = dotStyledExport(snapshot, options?.styles, options?.onMixedDirection);
|
|
1201
|
+
if (styled === null) {
|
|
1202
|
+
return checkPlain(snapshot, options);
|
|
1203
|
+
}
|
|
1204
|
+
return Object.freeze([...checkPlain(styled.snapshot, options), ...styled.notes]);
|
|
149
1205
|
},
|
|
150
1206
|
/**
|
|
151
1207
|
* Write the snapshot as UTF-8 chunks.
|
|
@@ -154,7 +1210,12 @@ const dotExporter = Object.freeze({
|
|
|
154
1210
|
* @returns the encoded chunks
|
|
155
1211
|
*/
|
|
156
1212
|
export(snapshot, options) {
|
|
157
|
-
return encodeChunks(
|
|
1213
|
+
return encodeChunks(
|
|
1214
|
+
writeDot(
|
|
1215
|
+
dotStyledExport(snapshot, options?.styles, options?.onMixedDirection)?.snapshot ?? snapshot,
|
|
1216
|
+
options
|
|
1217
|
+
)
|
|
1218
|
+
);
|
|
158
1219
|
},
|
|
159
1220
|
/**
|
|
160
1221
|
* Write the snapshot as one string.
|
|
@@ -163,9 +1224,24 @@ const dotExporter = Object.freeze({
|
|
|
163
1224
|
* @returns the whole document
|
|
164
1225
|
*/
|
|
165
1226
|
exportToString(snapshot, options) {
|
|
166
|
-
return joinText(
|
|
1227
|
+
return joinText(
|
|
1228
|
+
writeDot(
|
|
1229
|
+
dotStyledExport(snapshot, options?.styles, options?.onMixedDirection)?.snapshot ?? snapshot,
|
|
1230
|
+
options
|
|
1231
|
+
)
|
|
1232
|
+
);
|
|
167
1233
|
}
|
|
168
1234
|
});
|
|
1235
|
+
function checkPlain(snapshot, options) {
|
|
1236
|
+
const resolved = resolveExportOptions(options);
|
|
1237
|
+
const notes = checkCapabilities(snapshot, CAPABILITIES, resolved, {
|
|
1238
|
+
positionDtype: "f64",
|
|
1239
|
+
roles: KEPT_ROLES,
|
|
1240
|
+
roleNames: ROLE_NAMES
|
|
1241
|
+
});
|
|
1242
|
+
const plan = new ExportPlan(snapshot, resolved, options);
|
|
1243
|
+
return [...notes, ...plan.notes()];
|
|
1244
|
+
}
|
|
169
1245
|
function* writeDot(snapshot, options) {
|
|
170
1246
|
const resolved = resolveExportOptions(options);
|
|
171
1247
|
const plan = new ExportPlan(snapshot, resolved, options);
|
|
@@ -175,24 +1251,6 @@ function* writeDot(snapshot, options) {
|
|
|
175
1251
|
function endsWithBackslash(text) {
|
|
176
1252
|
return !isWritableDotText(text);
|
|
177
1253
|
}
|
|
178
|
-
function isHtmlString(text) {
|
|
179
|
-
if (text.length < 2 || !text.startsWith("<") || !text.endsWith(">")) {
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
let depth = 0;
|
|
183
|
-
for (let i = 0; i < text.length; i++) {
|
|
184
|
-
const c = text.charCodeAt(i);
|
|
185
|
-
if (c === 60) {
|
|
186
|
-
depth++;
|
|
187
|
-
} else if (c === 62) {
|
|
188
|
-
depth--;
|
|
189
|
-
if (depth === 0 && i !== text.length - 1) {
|
|
190
|
-
return false;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return depth === 0;
|
|
195
|
-
}
|
|
196
1254
|
function writeId(text) {
|
|
197
1255
|
return isHtmlString(text) ? text : quoteDotId(text);
|
|
198
1256
|
}
|
|
@@ -216,6 +1274,69 @@ function badOption(option, found, expected) {
|
|
|
216
1274
|
}
|
|
217
1275
|
);
|
|
218
1276
|
}
|
|
1277
|
+
function columnNotes(label, column, note) {
|
|
1278
|
+
const { name, role } = column.meta;
|
|
1279
|
+
const text = column.dtype === "string" || column.dtype === "dict";
|
|
1280
|
+
if (label !== "graph" && column.nullCount === column.length) {
|
|
1281
|
+
note(
|
|
1282
|
+
DOT_LOSS.EMPTY_COLUMN_DROPPED,
|
|
1283
|
+
`${label} column "${name}" has no set cell and is not written: DOT writes cells, never declarations`,
|
|
1284
|
+
name,
|
|
1285
|
+
0
|
|
1286
|
+
);
|
|
1287
|
+
return;
|
|
1288
|
+
}
|
|
1289
|
+
if (label !== "graph" && role === null && name === LABEL_ATTRIBUTE && text) {
|
|
1290
|
+
note(
|
|
1291
|
+
DOT_LOSS.ROLE_ASSUMED,
|
|
1292
|
+
`${label} column "${name}" reads back with the label role`,
|
|
1293
|
+
name,
|
|
1294
|
+
column.length - column.nullCount
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
const bad = column.dtype === "f32" || column.dtype === "f64" ? countNonFinite(column) : 0;
|
|
1298
|
+
if (bad > 0) {
|
|
1299
|
+
note(
|
|
1300
|
+
DOT_LOSS.NON_FINITE,
|
|
1301
|
+
`${label} column "${name}" holds ${bad} non-finite value${plural(bad)} with no numeric DOT spelling; they read back as text`,
|
|
1302
|
+
name,
|
|
1303
|
+
bad
|
|
1304
|
+
);
|
|
1305
|
+
}
|
|
1306
|
+
const typed = text && (role === null || !TEXT_ROLES.has(role)) ? countTypedLookingText(column) : 0;
|
|
1307
|
+
if (typed > 0) {
|
|
1308
|
+
note(
|
|
1309
|
+
DOT_LOSS.TEXT_INFERRED,
|
|
1310
|
+
`${label} column "${name}" holds ${typed} text value${plural(typed)} that look like numbers or booleans; DOT values are untyped and they read back as such`,
|
|
1311
|
+
name,
|
|
1312
|
+
typed
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
function positionNotes(snapshot, position, note) {
|
|
1317
|
+
if (position !== null && position.meta.components !== 2 && position.meta.components !== 3) {
|
|
1318
|
+
note(
|
|
1319
|
+
DOT_LOSS.POSITION_SHAPE,
|
|
1320
|
+
`node column "${position.meta.name}" (position) has ${position.meta.components} components and is not written; pos takes 2 or 3`,
|
|
1321
|
+
position.meta.name,
|
|
1322
|
+
position.length - position.nullCount
|
|
1323
|
+
);
|
|
1324
|
+
}
|
|
1325
|
+
for (const [label, table] of [
|
|
1326
|
+
["edge", snapshot.edges],
|
|
1327
|
+
["graph", snapshot.graph]
|
|
1328
|
+
]) {
|
|
1329
|
+
const column = table.byRole("position");
|
|
1330
|
+
if (column !== null) {
|
|
1331
|
+
note(
|
|
1332
|
+
DOT_LOSS.POSITION_SHAPE,
|
|
1333
|
+
`${label} column "${column.meta.name}" (position) is not written; only node positions map to pos`,
|
|
1334
|
+
column.meta.name,
|
|
1335
|
+
column.length - column.nullCount
|
|
1336
|
+
);
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
219
1340
|
class ExportPlan {
|
|
220
1341
|
/**
|
|
221
1342
|
* Plan one export.
|
|
@@ -264,6 +1385,49 @@ class ExportPlan {
|
|
|
264
1385
|
this.children = childrenCsr(snapshot, {
|
|
265
1386
|
column: this.parent !== null && this.parent.dtype === "u32" ? this.parent : null
|
|
266
1387
|
});
|
|
1388
|
+
this.nodeColumns = firstSeenOrder(this.nodeColumns, this.nodeTextOrder());
|
|
1389
|
+
const edgeRows = [];
|
|
1390
|
+
for (let e = 0; e < snapshot.edgeCount; e++) {
|
|
1391
|
+
if (!this.folding.folded(e)) {
|
|
1392
|
+
edgeRows.push(e);
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
this.edgeColumns = firstSeenOrder(this.edgeColumns, edgeRows);
|
|
1396
|
+
}
|
|
1397
|
+
/**
|
|
1398
|
+
* The nodes in the order a reader of the document takes their attributes: a node's statement before the members
|
|
1399
|
+
* of its cluster, and a cluster's own `graph [...]` attributes when its subgraph closes, after its members.
|
|
1400
|
+
* @returns the node indices
|
|
1401
|
+
*/
|
|
1402
|
+
nodeTextOrder() {
|
|
1403
|
+
const order = [];
|
|
1404
|
+
const seen = new Uint8Array(this.snapshot.nodeCount);
|
|
1405
|
+
const stack = [];
|
|
1406
|
+
for (let root = this.snapshot.nodeCount - 1; root >= 0; root--) {
|
|
1407
|
+
stack.push(root);
|
|
1408
|
+
}
|
|
1409
|
+
while (stack.length > 0) {
|
|
1410
|
+
const i = stack.pop();
|
|
1411
|
+
if (i < 0) {
|
|
1412
|
+
order.push(-i - 1);
|
|
1413
|
+
continue;
|
|
1414
|
+
}
|
|
1415
|
+
if (seen[i] === 1) {
|
|
1416
|
+
continue;
|
|
1417
|
+
}
|
|
1418
|
+
seen[i] = 1;
|
|
1419
|
+
const marked = this.cluster !== null && this.cluster.isSet(i) && this.cluster.value(i) === true;
|
|
1420
|
+
if (marked) {
|
|
1421
|
+
stack.push(-i - 1);
|
|
1422
|
+
} else {
|
|
1423
|
+
order.push(i);
|
|
1424
|
+
}
|
|
1425
|
+
const kids = this.children.childrenOf(i);
|
|
1426
|
+
for (let k = kids.length - 1; k >= 0; k--) {
|
|
1427
|
+
stack.push(kids[k]);
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
return order;
|
|
267
1431
|
}
|
|
268
1432
|
/**
|
|
269
1433
|
* Whether a node column is written as node attributes.
|
|
@@ -363,50 +1527,34 @@ class ExportPlan {
|
|
|
363
1527
|
["graph", this.graphColumns]
|
|
364
1528
|
]) {
|
|
365
1529
|
for (const column of columns) {
|
|
366
|
-
if (label
|
|
367
|
-
|
|
368
|
-
DOT_LOSS.EMPTY_COLUMN_DROPPED,
|
|
369
|
-
`${label} column "${column.meta.name}" has no set cell and is not written: DOT writes cells, never declarations`,
|
|
370
|
-
column.meta.name,
|
|
371
|
-
0
|
|
372
|
-
);
|
|
373
|
-
continue;
|
|
374
|
-
}
|
|
375
|
-
if (label !== "graph" && column.meta.role === null && column.meta.name === LABEL_ATTRIBUTE && (column.dtype === "string" || column.dtype === "dict")) {
|
|
376
|
-
note(
|
|
377
|
-
DOT_LOSS.ROLE_ASSUMED,
|
|
378
|
-
`${label} column "${column.meta.name}" reads back with the label role`,
|
|
379
|
-
column.meta.name,
|
|
380
|
-
column.length - column.nullCount
|
|
381
|
-
);
|
|
382
|
-
}
|
|
383
|
-
if (column.dtype === "f32" || column.dtype === "f64") {
|
|
384
|
-
const bad = countNonFinite(column);
|
|
385
|
-
if (bad > 0) {
|
|
386
|
-
note(
|
|
387
|
-
DOT_LOSS.NON_FINITE,
|
|
388
|
-
`${label} column "${column.meta.name}" holds ${bad} non-finite value${plural(bad)} with no numeric DOT spelling; they read back as text`,
|
|
389
|
-
column.meta.name,
|
|
390
|
-
bad
|
|
391
|
-
);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
if ((column.dtype === "string" || column.dtype === "dict") && (column.meta.role === null || !TEXT_ROLES.has(column.meta.role))) {
|
|
395
|
-
const typed = countTypedLookingText(column);
|
|
396
|
-
if (typed > 0) {
|
|
397
|
-
note(
|
|
398
|
-
DOT_LOSS.TEXT_INFERRED,
|
|
399
|
-
`${label} column "${column.meta.name}" holds ${typed} text value${plural(typed)} that look like numbers or booleans; DOT values are untyped and they read back as such`,
|
|
400
|
-
column.meta.name,
|
|
401
|
-
typed
|
|
402
|
-
);
|
|
403
|
-
}
|
|
1530
|
+
if (label === "graph") {
|
|
1531
|
+
notes.push(...charsetNotes(column));
|
|
404
1532
|
}
|
|
1533
|
+
columnNotes(label, column, note);
|
|
405
1534
|
}
|
|
406
1535
|
}
|
|
1536
|
+
this.structureNotes(note);
|
|
1537
|
+
positionNotes(snapshot, this.position, note);
|
|
1538
|
+
const textIds = countTextIds(snapshot);
|
|
1539
|
+
if (textIds > 0) {
|
|
1540
|
+
note(
|
|
1541
|
+
DOT_LOSS.ID_TEXT_TYPE,
|
|
1542
|
+
`${textIds} node id${plural(textIds)} ${agree(textIds, "reads", "read")} back as the other type under ids: "canonical" (a string "1" becomes 1, a number 1.5 becomes "1.5")`,
|
|
1543
|
+
null,
|
|
1544
|
+
textIds
|
|
1545
|
+
);
|
|
1546
|
+
}
|
|
1547
|
+
return notes;
|
|
1548
|
+
}
|
|
1549
|
+
/**
|
|
1550
|
+
* The notes of the graph's structure DOT changes: parents written as clusters, mutual pairs and parents lists.
|
|
1551
|
+
* @param note - the recorder
|
|
1552
|
+
*/
|
|
1553
|
+
structureNotes(note) {
|
|
1554
|
+
const { snapshot } = this;
|
|
407
1555
|
let unmarked = 0;
|
|
408
1556
|
for (let i = 0; i < snapshot.nodeCount; i++) {
|
|
409
|
-
const marked = this.cluster
|
|
1557
|
+
const marked = this.cluster?.isSet(i) === true && this.cluster.value(i) === true;
|
|
410
1558
|
if (!marked && this.children.childrenOf(i).length > 0) {
|
|
411
1559
|
unmarked++;
|
|
412
1560
|
}
|
|
@@ -437,38 +1585,6 @@ class ExportPlan {
|
|
|
437
1585
|
parents.length - parents.nullCount
|
|
438
1586
|
);
|
|
439
1587
|
}
|
|
440
|
-
if (this.position !== null && this.position.meta.components !== 2 && this.position.meta.components !== 3) {
|
|
441
|
-
note(
|
|
442
|
-
DOT_LOSS.POSITION_SHAPE,
|
|
443
|
-
`node column "${this.position.meta.name}" (position) has ${this.position.meta.components} components and is not written; pos takes 2 or 3`,
|
|
444
|
-
this.position.meta.name,
|
|
445
|
-
this.position.length - this.position.nullCount
|
|
446
|
-
);
|
|
447
|
-
}
|
|
448
|
-
for (const [label, table] of [
|
|
449
|
-
["edge", snapshot.edges],
|
|
450
|
-
["graph", snapshot.graph]
|
|
451
|
-
]) {
|
|
452
|
-
const column = table.byRole("position");
|
|
453
|
-
if (column !== null) {
|
|
454
|
-
note(
|
|
455
|
-
DOT_LOSS.POSITION_SHAPE,
|
|
456
|
-
`${label} column "${column.meta.name}" (position) is not written; only node positions map to pos`,
|
|
457
|
-
column.meta.name,
|
|
458
|
-
column.length - column.nullCount
|
|
459
|
-
);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
const textIds = countTextIds(snapshot);
|
|
463
|
-
if (textIds > 0) {
|
|
464
|
-
note(
|
|
465
|
-
DOT_LOSS.ID_TEXT_TYPE,
|
|
466
|
-
`${textIds} node id${plural(textIds)} ${agree(textIds, "reads", "read")} back as the other type under ids: "canonical" (a string "1" becomes 1, a number 1.5 becomes "1.5")`,
|
|
467
|
-
null,
|
|
468
|
-
textIds
|
|
469
|
-
);
|
|
470
|
-
}
|
|
471
|
-
return notes;
|
|
472
1588
|
}
|
|
473
1589
|
/**
|
|
474
1590
|
* Throw for the conditions check() reports as errors: mixed direction under "error", and an
|
|
@@ -700,7 +1816,10 @@ class ExportPlan {
|
|
|
700
1816
|
if (!column.isSet(row)) {
|
|
701
1817
|
continue;
|
|
702
1818
|
}
|
|
703
|
-
|
|
1819
|
+
let text = cellText(column, row);
|
|
1820
|
+
if (text !== null && columns === this.graphColumns && isCharset(column) && !UTF8_CHARSET.test(text)) {
|
|
1821
|
+
text = "UTF-8";
|
|
1822
|
+
}
|
|
704
1823
|
if (text !== null) {
|
|
705
1824
|
out.push(`${quoteDotId(this.attributeName(column))}=${writeId(text)}`);
|
|
706
1825
|
}
|
|
@@ -787,6 +1906,22 @@ function positionDims(column) {
|
|
|
787
1906
|
}
|
|
788
1907
|
return column.meta.components === 2 ? 2 : 3;
|
|
789
1908
|
}
|
|
1909
|
+
function firstSeenOrder(columns, rows) {
|
|
1910
|
+
const left = new Set(columns);
|
|
1911
|
+
const out = [];
|
|
1912
|
+
for (const row of rows) {
|
|
1913
|
+
if (left.size === 0) {
|
|
1914
|
+
break;
|
|
1915
|
+
}
|
|
1916
|
+
for (const column of columns) {
|
|
1917
|
+
if (left.has(column) && column.isSet(row) && cellText(column, row) !== null) {
|
|
1918
|
+
out.push(column);
|
|
1919
|
+
left.delete(column);
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
return [...out, ...left];
|
|
1924
|
+
}
|
|
790
1925
|
function cellText(column, row) {
|
|
791
1926
|
switch (column.dtype) {
|
|
792
1927
|
case "bool":
|
|
@@ -867,6 +2002,53 @@ function countTextIds(snapshot) {
|
|
|
867
2002
|
}
|
|
868
2003
|
return count;
|
|
869
2004
|
}
|
|
2005
|
+
const POINTS_PER_INCH = 72;
|
|
2006
|
+
function dotPositions(snapshot) {
|
|
2007
|
+
if (snapshot.nodes.byRole("position") === null) {
|
|
2008
|
+
return null;
|
|
2009
|
+
}
|
|
2010
|
+
const bb = snapshot.graph.get("bb");
|
|
2011
|
+
const laidOut = bb !== null && bb.isSet(0) && boxOf(bb.value(0)) !== null;
|
|
2012
|
+
const width = snapshot.nodes.get("width");
|
|
2013
|
+
const widths = [];
|
|
2014
|
+
for (let row = 0; width !== null && row < width.length; row++) {
|
|
2015
|
+
const w = width.isSet(row) ? Number(width.value(row)) : Number.NaN;
|
|
2016
|
+
if (Number.isFinite(w)) {
|
|
2017
|
+
widths.push(laidOut ? w * POINTS_PER_INCH : w);
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
return {
|
|
2021
|
+
units: laidOut ? "px" : "file",
|
|
2022
|
+
// input inches are drawn beside the styles' point lengths at 72 points each
|
|
2023
|
+
...laidOut ? {} : { pxPerUnit: POINTS_PER_INCH },
|
|
2024
|
+
yAxis: "up",
|
|
2025
|
+
groups: clusterBoxes(snapshot),
|
|
2026
|
+
medianNodeSize: median(widths),
|
|
2027
|
+
...laidOut ? { tool: "graphviz" } : {}
|
|
2028
|
+
};
|
|
2029
|
+
}
|
|
2030
|
+
function clusterBoxes(snapshot) {
|
|
2031
|
+
const bb = snapshot.nodes.get("bb");
|
|
2032
|
+
const out = [];
|
|
2033
|
+
for (let node = 0; bb !== null && node < bb.length; node++) {
|
|
2034
|
+
const box = bb.isSet(node) ? boxOf(bb.value(node)) : null;
|
|
2035
|
+
if (box !== null) {
|
|
2036
|
+
out.push({ node, box });
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
return out;
|
|
2040
|
+
}
|
|
2041
|
+
function boxOf(value) {
|
|
2042
|
+
if (typeof value !== "string") {
|
|
2043
|
+
return null;
|
|
2044
|
+
}
|
|
2045
|
+
const parts = value.split(",").map(Number);
|
|
2046
|
+
if (parts.length !== 4 || !parts.every(Number.isFinite)) {
|
|
2047
|
+
return null;
|
|
2048
|
+
}
|
|
2049
|
+
const [llx, lly, urx, ury] = parts;
|
|
2050
|
+
return { x: (llx + urx) / 2, y: (lly + ury) / 2, width: urx - llx, height: ury - lly };
|
|
2051
|
+
}
|
|
870
2052
|
class DotSyntaxError extends Error {
|
|
871
2053
|
/**
|
|
872
2054
|
* Create a syntax error.
|
|
@@ -1354,6 +2536,8 @@ const dotImporter = Object.freeze({
|
|
|
1354
2536
|
options: Object.freeze(["keepPositionSource", "mismatchedEdgeOperator", "positions"]),
|
|
1355
2537
|
extensions: EXTENSIONS,
|
|
1356
2538
|
mimeTypes: MIME_TYPES,
|
|
2539
|
+
styles: dotStyles,
|
|
2540
|
+
positions: dotPositions,
|
|
1357
2541
|
/**
|
|
1358
2542
|
* Confidence that the head of an input is DOT: the `[strict] graph | digraph` header after
|
|
1359
2543
|
* optional comments.
|
|
@@ -1765,22 +2949,41 @@ class DotParser {
|
|
|
1765
2949
|
}
|
|
1766
2950
|
throw new DotSyntaxError(`unexpected ${describeToken(token)} at the start of a statement`, token.line);
|
|
1767
2951
|
}
|
|
1768
|
-
if (!token.quoted && !token.html) {
|
|
1769
|
-
|
|
1770
|
-
if (keyword === "node" || keyword === "edge" || keyword === "graph") {
|
|
1771
|
-
lexer.next();
|
|
1772
|
-
this.attributeStatement(scope, keyword, token.line);
|
|
1773
|
-
return;
|
|
1774
|
-
}
|
|
1775
|
-
if (keyword === "subgraph") {
|
|
1776
|
-
const group = this.subgraph(scope);
|
|
1777
|
-
this.maybeEdgeStatement(scope, group, token.line);
|
|
1778
|
-
return;
|
|
1779
|
-
}
|
|
1780
|
-
if (keyword === "digraph" || keyword === "strict") {
|
|
1781
|
-
throw new DotSyntaxError(`unexpected keyword ${describeToken(token)} inside a graph`, token.line);
|
|
1782
|
-
}
|
|
2952
|
+
if (!token.quoted && !token.html && this.keywordStatement(scope, token)) {
|
|
2953
|
+
return;
|
|
1783
2954
|
}
|
|
2955
|
+
this.idStatement(scope);
|
|
2956
|
+
}
|
|
2957
|
+
/**
|
|
2958
|
+
* Parse a statement that starts with a keyword: an attribute statement or a subgraph.
|
|
2959
|
+
* @param scope - the scope
|
|
2960
|
+
* @param token - the statement's first token, not yet read
|
|
2961
|
+
* @returns false when the token is no statement keyword (an ID)
|
|
2962
|
+
*/
|
|
2963
|
+
keywordStatement(scope, token) {
|
|
2964
|
+
const keyword = token.text.toLowerCase();
|
|
2965
|
+
if (keyword === "node" || keyword === "edge" || keyword === "graph") {
|
|
2966
|
+
this.lexer.next();
|
|
2967
|
+
this.attributeStatement(scope, keyword, token.line);
|
|
2968
|
+
return true;
|
|
2969
|
+
}
|
|
2970
|
+
if (keyword === "subgraph") {
|
|
2971
|
+
const group = this.subgraph(scope);
|
|
2972
|
+
this.maybeEdgeStatement(scope, group, token.line);
|
|
2973
|
+
return true;
|
|
2974
|
+
}
|
|
2975
|
+
if (keyword === "digraph" || keyword === "strict") {
|
|
2976
|
+
throw new DotSyntaxError(`unexpected keyword ${describeToken(token)} inside a graph`, token.line);
|
|
2977
|
+
}
|
|
2978
|
+
return false;
|
|
2979
|
+
}
|
|
2980
|
+
/**
|
|
2981
|
+
* Parse a statement that starts with an ID: `ID = ID`, a node statement, or an edge statement starting with a
|
|
2982
|
+
* node.
|
|
2983
|
+
* @param scope - the scope
|
|
2984
|
+
*/
|
|
2985
|
+
idStatement(scope) {
|
|
2986
|
+
const { lexer } = this;
|
|
1784
2987
|
const id = this.identifier();
|
|
1785
2988
|
if (isPunct(lexer.peek(), "=")) {
|
|
1786
2989
|
lexer.next();
|
|
@@ -1789,6 +2992,10 @@ class DotParser {
|
|
|
1789
2992
|
return;
|
|
1790
2993
|
}
|
|
1791
2994
|
const port = this.port();
|
|
2995
|
+
if (isPunct(lexer.peek(), ",")) {
|
|
2996
|
+
this.nodeListStatement(scope, [{ id, port }, ...this.moreNodes()]);
|
|
2997
|
+
return;
|
|
2998
|
+
}
|
|
1792
2999
|
if (isEdgeOp(lexer.peek())) {
|
|
1793
3000
|
const endpoint = this.mentionEndpoint(scope, id, port);
|
|
1794
3001
|
this.edgeStatement(scope, endpoint === null ? [] : [endpoint], id.line);
|
|
@@ -1796,6 +3003,35 @@ class DotParser {
|
|
|
1796
3003
|
}
|
|
1797
3004
|
this.nodeStatement(scope, id, port);
|
|
1798
3005
|
}
|
|
3006
|
+
/**
|
|
3007
|
+
* Read the rest of a node list after its first node: `, ID [port]` repeated (`a, b, c`).
|
|
3008
|
+
* @returns the further nodes, in order
|
|
3009
|
+
*/
|
|
3010
|
+
moreNodes() {
|
|
3011
|
+
const out = [];
|
|
3012
|
+
while (isPunct(this.lexer.peek(), ",")) {
|
|
3013
|
+
this.lexer.next();
|
|
3014
|
+
const id = this.identifier();
|
|
3015
|
+
out.push({ id, port: this.port() });
|
|
3016
|
+
}
|
|
3017
|
+
return out;
|
|
3018
|
+
}
|
|
3019
|
+
/**
|
|
3020
|
+
* A statement starting with a node list (`a, b [attrs]` or `a, b -> c`): an edge statement from every node of
|
|
3021
|
+
* the list, or a node statement for each.
|
|
3022
|
+
* @param scope - the scope
|
|
3023
|
+
* @param nodes - the listed nodes with their ports
|
|
3024
|
+
*/
|
|
3025
|
+
nodeListStatement(scope, nodes) {
|
|
3026
|
+
if (isEdgeOp(this.lexer.peek())) {
|
|
3027
|
+
this.edgeStatement(scope, this.mentionAll(scope, nodes), nodes[0].id.line);
|
|
3028
|
+
return;
|
|
3029
|
+
}
|
|
3030
|
+
const attributes = this.attributeList();
|
|
3031
|
+
for (const n of nodes) {
|
|
3032
|
+
this.applyNodeStatement(scope, n.id, n.port, attributes);
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
1799
3035
|
/**
|
|
1800
3036
|
* Read an ID, concatenating quoted strings joined by `+`.
|
|
1801
3037
|
* @returns the id token (the concatenation keeps the first token's line and quoted flag)
|
|
@@ -2128,7 +3364,16 @@ class DotParser {
|
|
|
2128
3364
|
* @param port - the port, if any (dropped with a warning)
|
|
2129
3365
|
*/
|
|
2130
3366
|
nodeStatement(scope, id, port) {
|
|
2131
|
-
|
|
3367
|
+
this.applyNodeStatement(scope, id, port, this.attributeList());
|
|
3368
|
+
}
|
|
3369
|
+
/**
|
|
3370
|
+
* Mention a node of a node statement and apply the statement's attributes to it.
|
|
3371
|
+
* @param scope - the scope
|
|
3372
|
+
* @param id - the id token
|
|
3373
|
+
* @param port - the port, if any (dropped with a warning)
|
|
3374
|
+
* @param attributes - the statement's attributes
|
|
3375
|
+
*/
|
|
3376
|
+
applyNodeStatement(scope, id, port, attributes) {
|
|
2132
3377
|
const endpoint = this.mentionEndpoint(scope, id, null);
|
|
2133
3378
|
if (endpoint === null) {
|
|
2134
3379
|
return;
|
|
@@ -2174,20 +3419,35 @@ class DotParser {
|
|
|
2174
3419
|
groups.push(this.subgraph(scope));
|
|
2175
3420
|
} else {
|
|
2176
3421
|
const id = this.identifier();
|
|
2177
|
-
|
|
2178
|
-
const endpoint = this.mentionEndpoint(scope, id, port);
|
|
2179
|
-
groups.push(endpoint === null ? [] : [endpoint]);
|
|
3422
|
+
groups.push(this.mentionAll(scope, [{ id, port: this.port() }, ...this.moreNodes()]));
|
|
2180
3423
|
}
|
|
2181
3424
|
}
|
|
2182
3425
|
const attributes = this.attributeList();
|
|
2183
3426
|
for (let k = 0; k < kinds.length; k++) {
|
|
3427
|
+
const targets = groups[k + 1];
|
|
2184
3428
|
for (const source of groups[k]) {
|
|
2185
|
-
for (const target of
|
|
3429
|
+
for (const target of targets) {
|
|
2186
3430
|
this.pushEdge(scope, source, target, kinds[k], attributes, line);
|
|
2187
3431
|
}
|
|
2188
3432
|
}
|
|
2189
3433
|
}
|
|
2190
3434
|
}
|
|
3435
|
+
/**
|
|
3436
|
+
* Mention each listed node as an edge endpoint.
|
|
3437
|
+
* @param scope - the scope
|
|
3438
|
+
* @param nodes - the nodes with their ports
|
|
3439
|
+
* @returns the endpoints of the nodes that could be created
|
|
3440
|
+
*/
|
|
3441
|
+
mentionAll(scope, nodes) {
|
|
3442
|
+
const group = [];
|
|
3443
|
+
for (const n of nodes) {
|
|
3444
|
+
const endpoint = this.mentionEndpoint(scope, n.id, n.port);
|
|
3445
|
+
if (endpoint !== null) {
|
|
3446
|
+
group.push(endpoint);
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3449
|
+
return group;
|
|
3450
|
+
}
|
|
2191
3451
|
/**
|
|
2192
3452
|
* The direction of an edge from its operator, checked against the graph keyword.
|
|
2193
3453
|
* @param op - the operator token
|
|
@@ -2718,7 +3978,8 @@ class DotParser {
|
|
|
2718
3978
|
export {
|
|
2719
3979
|
DOT_ISSUE as D,
|
|
2720
3980
|
DOT_LOSS as a,
|
|
2721
|
-
|
|
3981
|
+
DOT_STYLE_CAPABILITIES as b,
|
|
3982
|
+
dotImporter as c,
|
|
2722
3983
|
dotExporter as d
|
|
2723
3984
|
};
|
|
2724
|
-
//# sourceMappingURL=importer-
|
|
3985
|
+
//# sourceMappingURL=importer-C2nzGhdV.js.map
|