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