@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
|
@@ -0,0 +1,930 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `graphty.styles` block: the rules of a graph's styles written into a file so that importing the file back into
|
|
3
|
+
* graphty rebuilds the same rules. The block is JSON; the per-element values its rules read are written beside it as
|
|
4
|
+
* element attributes named `graphty.style.<target>.<key>` (or, in a format with no per-element attributes, inside
|
|
5
|
+
* the block). A block is file input like any other: it is size-limited, validated member by member, never keyed into
|
|
6
|
+
* a plain object, and a block that fails any check is ignored with a reason code, never thrown.
|
|
7
|
+
*/
|
|
8
|
+
import { STYLE_ISSUE } from "../codes.js";
|
|
9
|
+
import { toolDefaults } from "../defaults.js";
|
|
10
|
+
import { featuresOf, heldEdgeRows, styleFingerprint } from "../plan/features.js";
|
|
11
|
+
import { plainCell, refSource, resolveRules, within } from "../plan/resolve.js";
|
|
12
|
+
import { STYLE_PROPERTIES } from "../vocabulary.js";
|
|
13
|
+
/**
|
|
14
|
+
* The name of the block in every format: a graph attribute, a key, an aspect or an archive entry.
|
|
15
|
+
* @category Styles
|
|
16
|
+
*/
|
|
17
|
+
export const STYLE_BLOCK_NAME = "graphty.styles";
|
|
18
|
+
/**
|
|
19
|
+
* The longest block graph-io reads, in characters; a longer one is ignored (`TOO_LARGE`).
|
|
20
|
+
* @category Styles
|
|
21
|
+
*/
|
|
22
|
+
export const MAX_STYLE_BLOCK_LENGTH = 16 * 1024 * 1024;
|
|
23
|
+
/** The deepest nesting of JSON values a block may have. */
|
|
24
|
+
const MAX_DEPTH = 64;
|
|
25
|
+
/** The most rules a block may hold. */
|
|
26
|
+
const MAX_RULES = 4096;
|
|
27
|
+
/** The longest id, key, property name or source field. */
|
|
28
|
+
const MAX_NAME = 256;
|
|
29
|
+
/** Keys that would reach an object's prototype; a block holding one anywhere is ignored. */
|
|
30
|
+
const FORBIDDEN_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
31
|
+
const TARGETS = ["node", "edge"];
|
|
32
|
+
const COMPUTED = new Set(["degree", "indegree", "outdegree"]);
|
|
33
|
+
/**
|
|
34
|
+
* The name of the element attribute holding one style column: `graphty.style.<target>.<key>`.
|
|
35
|
+
* @param target - nodes or edges
|
|
36
|
+
* @param key - the style column's key (`class`, `member.3`, `exceptions.fill`)
|
|
37
|
+
* @returns the attribute name
|
|
38
|
+
* @category Styles
|
|
39
|
+
*/
|
|
40
|
+
export function styleTag(target, key) {
|
|
41
|
+
return `graphty.style.${target}.${key}`;
|
|
42
|
+
}
|
|
43
|
+
/** The JSON escapes a reader of Cytoscape's convention would change, as `\u` escapes that mean the same. */
|
|
44
|
+
const SAFE_ESCAPES = {
|
|
45
|
+
"\\": String.raw `\u005c`,
|
|
46
|
+
n: String.raw `\u000a`,
|
|
47
|
+
t: String.raw `\u0009`,
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Writes a graph's styles as a `graphty.styles` block. Notes are not written. The output is deterministic: the same
|
|
51
|
+
* styles always give the same text. A backslash, newline or tab inside a string is written as a `\u` escape, so a
|
|
52
|
+
* format that decodes `\n` and `\t` in attribute values (Cytoscape's convention) reads the block back unchanged.
|
|
53
|
+
* @param extracted - the styles
|
|
54
|
+
* @param options - whether to write the style columns inside the block
|
|
55
|
+
* @returns the block's JSON text
|
|
56
|
+
* @category Styles
|
|
57
|
+
*/
|
|
58
|
+
export function writeStyleBlock(extracted, options = {}) {
|
|
59
|
+
const { styles, columns, fingerprint } = extracted;
|
|
60
|
+
const out = {
|
|
61
|
+
version: 1,
|
|
62
|
+
source: styles.source,
|
|
63
|
+
units: styles.units,
|
|
64
|
+
graph: styles.graph,
|
|
65
|
+
rules: styles.rules,
|
|
66
|
+
columns: { node: Array.from(columns.node.keys()), edge: Array.from(columns.edge.keys()) },
|
|
67
|
+
};
|
|
68
|
+
const booleanKeys = (byKey) => Array.from(byKey)
|
|
69
|
+
.filter(([, col]) => col.some((x) => x !== null) && col.every((x) => x === null || typeof x === "boolean"))
|
|
70
|
+
.map(([key]) => key);
|
|
71
|
+
const booleans = { node: booleanKeys(columns.node), edge: booleanKeys(columns.edge) };
|
|
72
|
+
if (booleans.node.length > 0 || booleans.edge.length > 0) {
|
|
73
|
+
out.booleans = booleans;
|
|
74
|
+
}
|
|
75
|
+
if (options.inlineColumns === true) {
|
|
76
|
+
if (options.snapshot !== undefined) {
|
|
77
|
+
const { ids, nodeCount } = options.snapshot;
|
|
78
|
+
out.order = Array.from({ length: nodeCount }, (_unused, i) => String(ids.idOf(i)));
|
|
79
|
+
}
|
|
80
|
+
// an edge's values are listed once per edge the file holds
|
|
81
|
+
const held = options.snapshot === undefined ? null : heldEdgeRows(options.snapshot);
|
|
82
|
+
out.values = {
|
|
83
|
+
node: Object.fromEntries(columns.node),
|
|
84
|
+
edge: Object.fromEntries(Array.from(columns.edge, ([key, col]) => [key, held === null ? col : held.map((e) => col[e] ?? null)])),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const { snapshot } = options;
|
|
88
|
+
if (snapshot !== undefined) {
|
|
89
|
+
const hashes = (target) => {
|
|
90
|
+
const table = target === "node" ? snapshot.nodes : snapshot.edges;
|
|
91
|
+
const n = target === "node" ? snapshot.nodeCount : snapshot.edgeCount;
|
|
92
|
+
// a name the reader refuses as a key is left out: its rules then find the column by its name alone
|
|
93
|
+
const read = dataNames(styles.rules.filter((r) => r.target === target))
|
|
94
|
+
.filter((c) => table.has(c) && !FORBIDDEN_KEYS.has(c) && c.length <= MAX_NAME)
|
|
95
|
+
.slice(0, MAX_RULES);
|
|
96
|
+
return Object.fromEntries(read.map((c) => [c, columnHash(table, c, n)]));
|
|
97
|
+
};
|
|
98
|
+
out.data = { node: hashes("node"), edge: hashes("edge") };
|
|
99
|
+
}
|
|
100
|
+
out.fingerprint = {
|
|
101
|
+
nodes: fingerprint.nodes,
|
|
102
|
+
edges: fingerprint.heldEdges ?? fingerprint.edges,
|
|
103
|
+
ids: fingerprint.ids,
|
|
104
|
+
};
|
|
105
|
+
return JSON.stringify(out).replaceAll(/\\(.)/g, (escape, c) => SAFE_ESCAPES[c] ?? escape);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The loss when graph-io would ignore a block it has just written: one longer than `MAX_STYLE_BLOCK_LENGTH`, or one
|
|
109
|
+
* past another limit the reader enforces (too many rules, a name too long). The format's own styles are still
|
|
110
|
+
* written, so importing the file back infers the rules again from them.
|
|
111
|
+
* @param text - the block's text, as `writeStyleBlock()` wrote it
|
|
112
|
+
* @param rules - how many rules the block holds
|
|
113
|
+
* @param check - "size" to check only the length: a block rewritten with its columns inline, whose rules were
|
|
114
|
+
* checked already
|
|
115
|
+
* @returns one `W_STYLE_RULES_NOT_KEPT` note naming the reason, or none when the block reads back
|
|
116
|
+
* @category Styles
|
|
117
|
+
*/
|
|
118
|
+
export function styleBlockLosses(text, rules, check = "all") {
|
|
119
|
+
let reason = null;
|
|
120
|
+
if (text.length > MAX_STYLE_BLOCK_LENGTH) {
|
|
121
|
+
reason = "TOO_LARGE";
|
|
122
|
+
}
|
|
123
|
+
else if (check === "all") {
|
|
124
|
+
const top = JSON.parse(text);
|
|
125
|
+
const { nodes, edges, ids } = top.fingerprint;
|
|
126
|
+
const parsed = parseStyleBlock(text, { nodes, edges, ids });
|
|
127
|
+
reason = parsed.ok ? null : parsed.reason;
|
|
128
|
+
}
|
|
129
|
+
if (reason === null) {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
return [
|
|
133
|
+
Object.freeze({
|
|
134
|
+
code: STYLE_ISSUE.RULES_NOT_KEPT,
|
|
135
|
+
message: `the ${STYLE_BLOCK_NAME} block would not read back (${reason}): the styles are written as the format's own, and importing the file infers the rules again`,
|
|
136
|
+
column: null,
|
|
137
|
+
count: rules,
|
|
138
|
+
}),
|
|
139
|
+
];
|
|
140
|
+
}
|
|
141
|
+
/** Thrown inside the validator only; turned into an `INVALID` result before parseStyleBlock() returns. */
|
|
142
|
+
class Invalid extends Error {
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Fails validation: throws `Invalid`, which parseStyleBlock() turns into an `INVALID` result.
|
|
146
|
+
* @throws Invalid always
|
|
147
|
+
*/
|
|
148
|
+
function invalid() {
|
|
149
|
+
throw new Invalid();
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Reads a `graphty.styles` block as untrusted input. It never throws: a block that is not text, too large, not JSON,
|
|
153
|
+
* of another version, nested too deep, holding a key that reaches a prototype (`__proto__`), shaped wrongly or
|
|
154
|
+
* written for a different graph is ignored with the reason.
|
|
155
|
+
* @param text - the block's text, as the file holds it
|
|
156
|
+
* @param fingerprint - the graph being imported (`styleFingerprint(snapshot)`)
|
|
157
|
+
* @returns the block, or why it is ignored
|
|
158
|
+
* @category Styles
|
|
159
|
+
*/
|
|
160
|
+
export function parseStyleBlock(text, fingerprint) {
|
|
161
|
+
if (typeof text !== "string") {
|
|
162
|
+
return { ok: false, reason: "INVALID" };
|
|
163
|
+
}
|
|
164
|
+
if (text.length > MAX_STYLE_BLOCK_LENGTH) {
|
|
165
|
+
return { ok: false, reason: "TOO_LARGE" };
|
|
166
|
+
}
|
|
167
|
+
let json;
|
|
168
|
+
try {
|
|
169
|
+
json = JSON.parse(text);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return { ok: false, reason: "NOT_JSON" };
|
|
173
|
+
}
|
|
174
|
+
if (!safeTree(json)) {
|
|
175
|
+
return { ok: false, reason: "INVALID" };
|
|
176
|
+
}
|
|
177
|
+
const top = isObject(json) ? json : null;
|
|
178
|
+
if (top === null) {
|
|
179
|
+
return { ok: false, reason: "INVALID" };
|
|
180
|
+
}
|
|
181
|
+
if (top.version !== 1) {
|
|
182
|
+
return { ok: false, reason: "VERSION" };
|
|
183
|
+
}
|
|
184
|
+
// a block for another graph says so, whatever else in it would not fit this one
|
|
185
|
+
const fp = isObject(top.fingerprint) ? top.fingerprint : null;
|
|
186
|
+
if (fp !== null &&
|
|
187
|
+
(fp.nodes !== fingerprint.nodes ||
|
|
188
|
+
fp.edges !== (fingerprint.heldEdges ?? fingerprint.edges) ||
|
|
189
|
+
fp.ids !== fingerprint.ids)) {
|
|
190
|
+
return { ok: false, reason: "FINGERPRINT" };
|
|
191
|
+
}
|
|
192
|
+
let block;
|
|
193
|
+
try {
|
|
194
|
+
block = readBlock(top);
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
if (err instanceof Invalid) {
|
|
198
|
+
return { ok: false, reason: "INVALID" };
|
|
199
|
+
}
|
|
200
|
+
throw err;
|
|
201
|
+
}
|
|
202
|
+
const f = block.fingerprint;
|
|
203
|
+
if (f.nodes !== fingerprint.nodes ||
|
|
204
|
+
f.edges !== (fingerprint.heldEdges ?? fingerprint.edges) ||
|
|
205
|
+
f.ids !== fingerprint.ids) {
|
|
206
|
+
return { ok: false, reason: "FINGERPRINT" };
|
|
207
|
+
}
|
|
208
|
+
return { ok: true, block };
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Whether a parsed JSON value is at most `MAX_DEPTH` deep and holds no key that reaches a prototype. Walked with an
|
|
212
|
+
* explicit stack, never by recursion.
|
|
213
|
+
* @param root - the parsed value
|
|
214
|
+
* @returns true when safe
|
|
215
|
+
*/
|
|
216
|
+
function safeTree(root) {
|
|
217
|
+
const stack = [[root, 0]];
|
|
218
|
+
while (stack.length > 0) {
|
|
219
|
+
const [v, depth] = stack.pop();
|
|
220
|
+
if (v === null || typeof v !== "object") {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (depth >= MAX_DEPTH || (!Array.isArray(v) && Object.keys(v).some((key) => FORBIDDEN_KEYS.has(key)))) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
const items = Array.isArray(v) ? v : Object.values(v);
|
|
227
|
+
for (const item of items) {
|
|
228
|
+
if (item !== null && typeof item === "object") {
|
|
229
|
+
stack.push([item, depth + 1]);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Whether a value is a plain JSON object (not an array, not null).
|
|
237
|
+
* @param v - the value
|
|
238
|
+
* @returns true for an object
|
|
239
|
+
*/
|
|
240
|
+
function isObject(v) {
|
|
241
|
+
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* A short string, or invalid.
|
|
245
|
+
* @param v - the value
|
|
246
|
+
* @returns the string
|
|
247
|
+
*/
|
|
248
|
+
function name(v) {
|
|
249
|
+
return typeof v === "string" && v.length <= MAX_NAME ? v : invalid();
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* A short string or null, or invalid.
|
|
253
|
+
* @param v - the value
|
|
254
|
+
* @returns the string or null
|
|
255
|
+
*/
|
|
256
|
+
function nameOrNull(v) {
|
|
257
|
+
return v === null || v === undefined ? null : name(v);
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Whether a value is a scalar: a string, a finite number or a boolean.
|
|
261
|
+
* @param v - the value
|
|
262
|
+
* @returns true for a scalar
|
|
263
|
+
*/
|
|
264
|
+
function isScalar(v) {
|
|
265
|
+
return typeof v === "string" || typeof v === "boolean" || (typeof v === "number" && Number.isFinite(v));
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* A scalar, or invalid.
|
|
269
|
+
* @param v - the value
|
|
270
|
+
* @returns the scalar
|
|
271
|
+
*/
|
|
272
|
+
function scalar(v) {
|
|
273
|
+
return isScalar(v) ? v : invalid();
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* An array, or invalid.
|
|
277
|
+
* @param v - the value
|
|
278
|
+
* @param max - the most items allowed
|
|
279
|
+
* @returns the array
|
|
280
|
+
*/
|
|
281
|
+
function array(v, max) {
|
|
282
|
+
return Array.isArray(v) && v.length <= max ? v : invalid();
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* The whole block.
|
|
286
|
+
* @param top - the parsed object
|
|
287
|
+
* @returns the block
|
|
288
|
+
*/
|
|
289
|
+
function readBlock(top) {
|
|
290
|
+
const source = isObject(top.source) ? top.source : invalid();
|
|
291
|
+
const units = isObject(top.units) ? top.units : invalid();
|
|
292
|
+
const length = units.length === "px" || units.length === "relative" ? units.length : invalid();
|
|
293
|
+
const fp = isObject(top.fingerprint) ? top.fingerprint : invalid();
|
|
294
|
+
const count = (v) => (typeof v === "number" && Number.isSafeInteger(v) && v >= 0 ? v : invalid());
|
|
295
|
+
const cols = isObject(top.columns) ? top.columns : invalid();
|
|
296
|
+
const block = {
|
|
297
|
+
version: 1,
|
|
298
|
+
source: { format: name(source.format), dialect: nameOrNull(source.dialect), tool: nameOrNull(source.tool) },
|
|
299
|
+
units: { length },
|
|
300
|
+
graph: values(top.graph ?? {}),
|
|
301
|
+
rules: array(top.rules, MAX_RULES).map(readRule),
|
|
302
|
+
columns: {
|
|
303
|
+
node: array(cols.node, MAX_RULES).map(name),
|
|
304
|
+
edge: array(cols.edge, MAX_RULES).map(name),
|
|
305
|
+
},
|
|
306
|
+
fingerprint: { nodes: count(fp.nodes), edges: count(fp.edges), ids: name(fp.ids) },
|
|
307
|
+
};
|
|
308
|
+
const read = top.data === undefined ? block : { ...block, data: readData(top.data) };
|
|
309
|
+
const withData = top.booleans === undefined ? read : { ...read, booleans: readBooleans(top.booleans) };
|
|
310
|
+
if (top.values === undefined) {
|
|
311
|
+
return withData;
|
|
312
|
+
}
|
|
313
|
+
const order = top.order === undefined ? undefined : readOrder(top.order, block.fingerprint.nodes);
|
|
314
|
+
const inline = readInline(top.values, block);
|
|
315
|
+
return { ...withData, ...(order === undefined ? {} : { order }), values: inline };
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* The boolean style columns of a block, by target.
|
|
319
|
+
* @param v - the parsed `booleans` member
|
|
320
|
+
* @returns the column keys
|
|
321
|
+
*/
|
|
322
|
+
function readBooleans(v) {
|
|
323
|
+
const booleans = isObject(v) ? v : invalid();
|
|
324
|
+
return {
|
|
325
|
+
node: array(booleans.node ?? [], MAX_RULES).map(name),
|
|
326
|
+
edge: array(booleans.edge ?? [], MAX_RULES).map(name),
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* The node ids of a block, in the order its inline values list the nodes.
|
|
331
|
+
* @param v - the parsed `order` member
|
|
332
|
+
* @param nodes - the node count of its fingerprint
|
|
333
|
+
* @returns the ids
|
|
334
|
+
*/
|
|
335
|
+
function readOrder(v, nodes) {
|
|
336
|
+
const order = array(v, nodes).map((id) => (typeof id === "string" ? id : invalid()));
|
|
337
|
+
return order.length === nodes ? order : invalid();
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* The style columns written inside a block: one value per node or edge for each column the block names.
|
|
341
|
+
* @param v - the parsed `values` member
|
|
342
|
+
* @param block - the block read so far
|
|
343
|
+
* @returns the columns, by target
|
|
344
|
+
*/
|
|
345
|
+
function readInline(v, block) {
|
|
346
|
+
const values = isObject(v) ? v : invalid();
|
|
347
|
+
const inline = { node: new Map(), edge: new Map() };
|
|
348
|
+
for (const target of TARGETS) {
|
|
349
|
+
const n = target === "node" ? block.fingerprint.nodes : block.fingerprint.edges;
|
|
350
|
+
const byKey = isObject(values[target]) ? values[target] : invalid();
|
|
351
|
+
for (const key of block.columns[target]) {
|
|
352
|
+
const col = array(Object.hasOwn(byKey, key) ? byKey[key] : invalid(), n);
|
|
353
|
+
if (col.length !== n) {
|
|
354
|
+
invalid();
|
|
355
|
+
}
|
|
356
|
+
inline[target].set(key, col.map((x) => (x === null ? null : scalar(x))));
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return inline;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* The data column hashes of a block.
|
|
363
|
+
* @param v - the parsed `data` member
|
|
364
|
+
* @returns the hashes by column name, per target
|
|
365
|
+
*/
|
|
366
|
+
function readData(v) {
|
|
367
|
+
const d = isObject(v) ? v : invalid();
|
|
368
|
+
const byTarget = (t) => {
|
|
369
|
+
const o = isObject(t) ? t : invalid();
|
|
370
|
+
const keys = Object.keys(o);
|
|
371
|
+
if (keys.length > MAX_RULES) {
|
|
372
|
+
invalid();
|
|
373
|
+
}
|
|
374
|
+
return new Map(keys.map((k) => [name(k), name(o[k])]));
|
|
375
|
+
};
|
|
376
|
+
return { node: byTarget(d.node), edge: byTarget(d.edge) };
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* A cell's value as text: a list as JSON, no value as a character no text holds.
|
|
380
|
+
* @param v - the cell
|
|
381
|
+
* @returns the text
|
|
382
|
+
*/
|
|
383
|
+
function cellText(v) {
|
|
384
|
+
if (v === null) {
|
|
385
|
+
return "\u0001";
|
|
386
|
+
}
|
|
387
|
+
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
|
|
388
|
+
return String(v);
|
|
389
|
+
}
|
|
390
|
+
return JSON.stringify(v);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* A hash of a column's values as text, by element index: the text of a value, so a format that reads the number 7
|
|
394
|
+
* back as "7" keeps the hash.
|
|
395
|
+
* @param table - the node or edge table
|
|
396
|
+
* @param column - the column's name
|
|
397
|
+
* @param n - the element count
|
|
398
|
+
* @returns the hash
|
|
399
|
+
*/
|
|
400
|
+
function columnHash(table, column, n) {
|
|
401
|
+
let h1 = 0x811c9dc5;
|
|
402
|
+
let h2 = 0x01000193 ^ 0x5bd1e995;
|
|
403
|
+
for (let i = 0; i < n; i++) {
|
|
404
|
+
const text = `${cellText(plainCell(table.value(column, i)))}\u0000`;
|
|
405
|
+
for (let c = 0; c < text.length; c++) {
|
|
406
|
+
const code = text.charCodeAt(c); // NOSONAR(S7758): hashes UTF-16 code units; code points would change every written hash
|
|
407
|
+
h1 = Math.imul(h1 ^ code, 0x01000193);
|
|
408
|
+
h2 = Math.imul(h2 ^ code, 0x01000193) ^ (h2 >>> 13);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
const hex = (h) => (h >>> 0).toString(16).padStart(8, "0");
|
|
412
|
+
return hex(h1) + hex(h2);
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Every data column some rule reads, in first-read order. A rule's `ext` is the consumer's own and is not read.
|
|
416
|
+
* @param rules - the rules
|
|
417
|
+
* @returns the column names
|
|
418
|
+
*/
|
|
419
|
+
function dataNames(rules) {
|
|
420
|
+
const out = new Set();
|
|
421
|
+
for (const { ext: _ext, ...rule } of rules) {
|
|
422
|
+
JSON.stringify(rule, (_k, v) => {
|
|
423
|
+
if (isObject(v) && typeof v.data === "string" && Object.keys(v).length === 1) {
|
|
424
|
+
out.add(v.data);
|
|
425
|
+
}
|
|
426
|
+
return v;
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
return [...out];
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* A rule with its data column references renamed; its `ext` is kept untouched.
|
|
433
|
+
* @param rule - the rule
|
|
434
|
+
* @param rename - the new name of each column that moved
|
|
435
|
+
* @returns the rule
|
|
436
|
+
*/
|
|
437
|
+
function renameData(rule, rename) {
|
|
438
|
+
const { ext, ...rest } = rule;
|
|
439
|
+
const moved = JSON.parse(JSON.stringify(rest, (_k, v) => isObject(v) && typeof v.data === "string" && Object.keys(v).length === 1 && rename.has(v.data)
|
|
440
|
+
? { data: rename.get(v.data) }
|
|
441
|
+
: v));
|
|
442
|
+
return ext === undefined ? moved : { ...moved, ext };
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Where each data column a block's rules read is in the imported graph: under its own name when its values are the
|
|
446
|
+
* same, else the first column holding the same values (a format that renamed it), else under its own name.
|
|
447
|
+
* @param block - the block
|
|
448
|
+
* @param snapshot - the graph
|
|
449
|
+
* @param target - nodes or edges
|
|
450
|
+
* @returns the new name of each column that moved
|
|
451
|
+
*/
|
|
452
|
+
function movedColumns(block, snapshot, target) {
|
|
453
|
+
const moved = new Map();
|
|
454
|
+
const want = block.data?.[target];
|
|
455
|
+
if (want === undefined || want.size === 0) {
|
|
456
|
+
return moved;
|
|
457
|
+
}
|
|
458
|
+
const table = target === "node" ? snapshot.nodes : snapshot.edges;
|
|
459
|
+
const n = target === "node" ? snapshot.nodeCount : snapshot.edgeCount;
|
|
460
|
+
let have = null;
|
|
461
|
+
for (const [column, hash] of want) {
|
|
462
|
+
if (table.has(column) && columnHash(table, column, n) === hash) {
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
have ?? (have = new Map(Array.from(table.names(), (c) => [c, columnHash(table, c, n)])));
|
|
466
|
+
for (const [c, h] of have) {
|
|
467
|
+
if (h === hash) {
|
|
468
|
+
moved.set(column, c);
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return moved;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* A record of style values, copied into a null-prototype object.
|
|
477
|
+
* @param v - the parsed record
|
|
478
|
+
* @returns the copy
|
|
479
|
+
*/
|
|
480
|
+
function values(v) {
|
|
481
|
+
const o = isObject(v) ? v : invalid();
|
|
482
|
+
const out = Object.create(null);
|
|
483
|
+
for (const key of Object.keys(o)) {
|
|
484
|
+
out[name(key)] = scalar(o[key]);
|
|
485
|
+
}
|
|
486
|
+
return out;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* One rule.
|
|
490
|
+
* @param v - the parsed rule
|
|
491
|
+
* @returns the rule
|
|
492
|
+
*/
|
|
493
|
+
function readRule(v) {
|
|
494
|
+
const r = isObject(v) ? v : invalid();
|
|
495
|
+
const target = r.target === "node" || r.target === "edge" ? r.target : invalid();
|
|
496
|
+
const rule = {
|
|
497
|
+
id: name(r.id),
|
|
498
|
+
target,
|
|
499
|
+
role: name(r.role),
|
|
500
|
+
origin: name(r.origin),
|
|
501
|
+
where: predicate(r.where),
|
|
502
|
+
};
|
|
503
|
+
if (r.set !== undefined) {
|
|
504
|
+
rule.set = values(r.set);
|
|
505
|
+
}
|
|
506
|
+
if (r.map !== undefined) {
|
|
507
|
+
const m = isObject(r.map) ? r.map : invalid();
|
|
508
|
+
const map = Object.create(null);
|
|
509
|
+
for (const key of Object.keys(m)) {
|
|
510
|
+
map[name(key)] = mapping(m[key]);
|
|
511
|
+
}
|
|
512
|
+
rule.map = map;
|
|
513
|
+
}
|
|
514
|
+
if (r.facts !== undefined) {
|
|
515
|
+
rule.facts = facts(r.facts);
|
|
516
|
+
}
|
|
517
|
+
if (r.ext !== undefined) {
|
|
518
|
+
// carried untouched for the consumer that wrote it; safeTree() already checked its keys and depth
|
|
519
|
+
rule.ext = isObject(r.ext) ? r.ext : invalid();
|
|
520
|
+
}
|
|
521
|
+
return rule;
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* A column reference.
|
|
525
|
+
* @param v - the parsed reference
|
|
526
|
+
* @returns the reference
|
|
527
|
+
*/
|
|
528
|
+
function columnRef(v) {
|
|
529
|
+
const o = isObject(v) ? v : invalid();
|
|
530
|
+
if (typeof o.data === "string") {
|
|
531
|
+
return { data: name(o.data) };
|
|
532
|
+
}
|
|
533
|
+
if (typeof o.style === "string") {
|
|
534
|
+
return { style: name(o.style) };
|
|
535
|
+
}
|
|
536
|
+
if (typeof o.computed === "string" && COMPUTED.has(o.computed)) {
|
|
537
|
+
return { computed: o.computed };
|
|
538
|
+
}
|
|
539
|
+
return invalid();
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* A predicate. A predicate of a kind this version does not know is kept as it is and matches nothing.
|
|
543
|
+
* @param v - the parsed predicate
|
|
544
|
+
* @returns the predicate
|
|
545
|
+
*/
|
|
546
|
+
function predicate(v) {
|
|
547
|
+
const o = isObject(v) ? v : invalid();
|
|
548
|
+
if ("all" in o) {
|
|
549
|
+
return o.all === true ? { all: true } : invalid();
|
|
550
|
+
}
|
|
551
|
+
if ("has" in o) {
|
|
552
|
+
return { has: columnRef(o.has) };
|
|
553
|
+
}
|
|
554
|
+
if ("eq" in o) {
|
|
555
|
+
const t = array(o.eq, 2);
|
|
556
|
+
return t.length === 2 ? { eq: [columnRef(t[0]), scalar(t[1])] } : invalid();
|
|
557
|
+
}
|
|
558
|
+
if ("in" in o) {
|
|
559
|
+
const t = array(o.in, 2);
|
|
560
|
+
return t.length === 2 ? { in: [columnRef(t[0]), array(t[1], 65536).map(scalar)] } : invalid();
|
|
561
|
+
}
|
|
562
|
+
if ("and" in o) {
|
|
563
|
+
return { and: array(o.and, 64).map(predicate) };
|
|
564
|
+
}
|
|
565
|
+
if ("or" in o) {
|
|
566
|
+
return { or: array(o.or, 64).map(predicate) };
|
|
567
|
+
}
|
|
568
|
+
if ("not" in o) {
|
|
569
|
+
return { not: predicate(o.not) };
|
|
570
|
+
}
|
|
571
|
+
return o;
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* A mapping. A mapping of a kind this version does not know is kept and gives no value.
|
|
575
|
+
* @param v - the parsed mapping
|
|
576
|
+
* @returns the mapping
|
|
577
|
+
*/
|
|
578
|
+
function mapping(v) {
|
|
579
|
+
const o = isObject(v) ? v : invalid();
|
|
580
|
+
const by = columnRef(o.by);
|
|
581
|
+
switch (o.kind) {
|
|
582
|
+
case "passthrough":
|
|
583
|
+
return { kind: "passthrough", by };
|
|
584
|
+
case "discrete":
|
|
585
|
+
return {
|
|
586
|
+
kind: "discrete",
|
|
587
|
+
by,
|
|
588
|
+
table: array(o.table, 1 << 20).map((pair) => {
|
|
589
|
+
const p = array(pair, 2);
|
|
590
|
+
return p.length === 2 ? [scalar(p[0]), scalar(p[1])] : invalid();
|
|
591
|
+
}),
|
|
592
|
+
};
|
|
593
|
+
case "continuous":
|
|
594
|
+
return {
|
|
595
|
+
kind: "continuous",
|
|
596
|
+
by,
|
|
597
|
+
points: array(o.points, 4096).map((pt) => {
|
|
598
|
+
const q = isObject(pt) ? pt : invalid();
|
|
599
|
+
return {
|
|
600
|
+
at: typeof q.at === "number" && Number.isFinite(q.at) ? q.at : invalid(),
|
|
601
|
+
below: scalar(q.below),
|
|
602
|
+
value: scalar(q.value),
|
|
603
|
+
above: scalar(q.above),
|
|
604
|
+
};
|
|
605
|
+
}),
|
|
606
|
+
};
|
|
607
|
+
default:
|
|
608
|
+
return { ...o, kind: name(o.kind), by };
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* A rule's facts: the known members, each checked; anything else is left out.
|
|
613
|
+
* @param v - the parsed facts
|
|
614
|
+
* @returns the facts
|
|
615
|
+
*/
|
|
616
|
+
function facts(v) {
|
|
617
|
+
const o = isObject(v) ? v : invalid();
|
|
618
|
+
const count = (x) => typeof x === "number" && Number.isSafeInteger(x) && x >= 0 ? x : undefined;
|
|
619
|
+
const out = {};
|
|
620
|
+
const elements = count(o.elements);
|
|
621
|
+
const classes = count(o.classes);
|
|
622
|
+
const distinctValues = count(o.distinctValues);
|
|
623
|
+
if (elements !== undefined) {
|
|
624
|
+
out.elements = elements;
|
|
625
|
+
}
|
|
626
|
+
if (classes !== undefined) {
|
|
627
|
+
out.classes = classes;
|
|
628
|
+
}
|
|
629
|
+
if (distinctValues !== undefined) {
|
|
630
|
+
out.distinctValues = distinctValues;
|
|
631
|
+
}
|
|
632
|
+
if (typeof o.reason === "string") {
|
|
633
|
+
out.reason = name(o.reason);
|
|
634
|
+
}
|
|
635
|
+
if (o.names !== undefined) {
|
|
636
|
+
out.names = array(o.names, 1 << 20).map((pair) => {
|
|
637
|
+
const p = array(pair, 2);
|
|
638
|
+
return p.length === 2 ? [scalar(p[0]), String(scalar(p[1]))] : invalid();
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
return out;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* The style columns a block's rules read, from the block itself or from the tagged element attributes of the
|
|
645
|
+
* snapshot; null when one is missing.
|
|
646
|
+
* @param block - the block
|
|
647
|
+
* @param snapshot - the graph
|
|
648
|
+
* @param target - nodes or edges
|
|
649
|
+
* @returns the columns by key, or null
|
|
650
|
+
*/
|
|
651
|
+
function blockColumns(block, snapshot, target) {
|
|
652
|
+
const out = new Map();
|
|
653
|
+
const table = target === "node" ? snapshot.nodes : snapshot.edges;
|
|
654
|
+
const n = target === "node" ? snapshot.nodeCount : snapshot.edgeCount;
|
|
655
|
+
for (const key of block.columns[target]) {
|
|
656
|
+
const inline = block.values?.[target].get(key);
|
|
657
|
+
if (inline !== undefined) {
|
|
658
|
+
out.set(key, target === "node" ? inNodeOrder(block, snapshot, inline) : onEdgeRows(snapshot, inline));
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
const tag = styleTag(target, key);
|
|
662
|
+
if (!table.has(tag)) {
|
|
663
|
+
return null;
|
|
664
|
+
}
|
|
665
|
+
const col = Array.from({ length: n }, (_, i) => {
|
|
666
|
+
const v = plainCell(table.value(tag, i));
|
|
667
|
+
return isScalar(v) ? v : null;
|
|
668
|
+
});
|
|
669
|
+
out.set(key, target === "edge" ? withPairValues(snapshot, col) : col);
|
|
670
|
+
}
|
|
671
|
+
return out;
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* The style columns the block lists as booleans, as booleans: a format with no booleans (GML) holds them as 0 and 1
|
|
675
|
+
* (or their text).
|
|
676
|
+
* @param block - the block
|
|
677
|
+
* @param columns - the style columns per target, changed in place
|
|
678
|
+
*/
|
|
679
|
+
function asBooleans(block, columns) {
|
|
680
|
+
for (const target of TARGETS) {
|
|
681
|
+
for (const key of block.booleans?.[target] ?? []) {
|
|
682
|
+
const col = columns[target].get(key);
|
|
683
|
+
if (col !== undefined) {
|
|
684
|
+
columns[target].set(key, col.map(asBoolean));
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* A value of a boolean style column as a boolean: 1 and 0, and their text, as GML and untyped formats hold them.
|
|
691
|
+
* @param v - the value read
|
|
692
|
+
* @returns the boolean, or the value when it is neither
|
|
693
|
+
*/
|
|
694
|
+
function asBoolean(v) {
|
|
695
|
+
if (v === 1 || v === "1" || v === "true") {
|
|
696
|
+
return true;
|
|
697
|
+
}
|
|
698
|
+
return v === 0 || v === "0" || v === "false" ? false : v;
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Inline node values in the order of the graph read back: by each node's id, when the block lists the order it wrote
|
|
702
|
+
* them in and the file read its nodes back in another.
|
|
703
|
+
* @param block - the block
|
|
704
|
+
* @param snapshot - the graph
|
|
705
|
+
* @param col - the values in the block's order
|
|
706
|
+
* @returns the values per node row
|
|
707
|
+
*/
|
|
708
|
+
function inNodeOrder(block, snapshot, col) {
|
|
709
|
+
const { order } = block;
|
|
710
|
+
if (order === undefined || order.every((id, i) => id === String(snapshot.ids.idOf(i)))) {
|
|
711
|
+
return col;
|
|
712
|
+
}
|
|
713
|
+
const at = new Map();
|
|
714
|
+
order.forEach((id, i) => {
|
|
715
|
+
if (!at.has(id)) {
|
|
716
|
+
at.set(id, i);
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
return Array.from({ length: snapshot.nodeCount }, (_unused, i) => col[at.get(String(snapshot.ids.idOf(i))) ?? -1] ?? null);
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Inline edge values, listed once per edge the file holds, per edge row: both halves of an undirected edge in a
|
|
723
|
+
* directed graph take the edge's value.
|
|
724
|
+
* @param snapshot - the graph
|
|
725
|
+
* @param col - the values per held edge
|
|
726
|
+
* @returns the values per edge row
|
|
727
|
+
*/
|
|
728
|
+
function onEdgeRows(snapshot, col) {
|
|
729
|
+
const held = heldEdgeRows(snapshot);
|
|
730
|
+
if (held.length === snapshot.edgeCount) {
|
|
731
|
+
return col;
|
|
732
|
+
}
|
|
733
|
+
const out = new Array(snapshot.edgeCount).fill(null);
|
|
734
|
+
held.forEach((e, k) => {
|
|
735
|
+
out[e] = col[k] ?? null;
|
|
736
|
+
});
|
|
737
|
+
return withPairValues(snapshot, out);
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* Per-edge values with each half of an undirected edge in a directed graph given its other half's value where it has
|
|
741
|
+
* none: the file holds the edge once, and the format reads its values onto one half.
|
|
742
|
+
* @param snapshot - the graph
|
|
743
|
+
* @param col - the values per edge row
|
|
744
|
+
* @returns the values
|
|
745
|
+
*/
|
|
746
|
+
function withPairValues(snapshot, col) {
|
|
747
|
+
const pair = snapshot.edges.byRole("pair");
|
|
748
|
+
if (pair === null) {
|
|
749
|
+
return col;
|
|
750
|
+
}
|
|
751
|
+
for (let i = 0; i < col.length; i++) {
|
|
752
|
+
if (col[i] === null && pair.isSet(i)) {
|
|
753
|
+
col[i] = col[pair.value(i)] ?? null;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
return col;
|
|
757
|
+
}
|
|
758
|
+
/** The color property whose alpha carries an opacity, and that opacity, per target. */
|
|
759
|
+
const ALPHA_SLOT = {
|
|
760
|
+
node: ["fill", "fillOpacity"],
|
|
761
|
+
edge: ["color", "opacity"],
|
|
762
|
+
};
|
|
763
|
+
/**
|
|
764
|
+
* The native values with opacity 1 wherever the color is opaque (it has a color and no opacity) and the rules give a
|
|
765
|
+
* translucent opacity: a format that writes the opacity as the color's alpha states 1 with an opaque color.
|
|
766
|
+
* @param values - the native values of one target
|
|
767
|
+
* @param target - nodes or edges
|
|
768
|
+
* @param rules - the block's rules
|
|
769
|
+
* @param src - the values the rules read
|
|
770
|
+
* @param n - the element count
|
|
771
|
+
* @returns the values, the opacity column replaced where it changes
|
|
772
|
+
*/
|
|
773
|
+
function opaqueColors(values, target, rules, src, n) {
|
|
774
|
+
const [colorProperty, opacityProperty] = ALPHA_SLOT[target];
|
|
775
|
+
const color = values[colorProperty];
|
|
776
|
+
if (color === undefined) {
|
|
777
|
+
return values;
|
|
778
|
+
}
|
|
779
|
+
const native = values[opacityProperty];
|
|
780
|
+
const resolved = resolveRules(rules, target, opacityProperty, src);
|
|
781
|
+
let out = null;
|
|
782
|
+
for (let i = 0; i < n; i++) {
|
|
783
|
+
const r = resolved[i];
|
|
784
|
+
if ((color[i] ?? null) !== null && (native?.[i] ?? null) === null && r !== null && r !== 1) {
|
|
785
|
+
out ?? (out = native === undefined ? new Array(n).fill(null) : [...native]);
|
|
786
|
+
out[i] = 1;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
return out === null ? values : { ...values, [opacityProperty]: out };
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* A name not yet taken: the base, else the base with `#2`, `#3` and so on.
|
|
793
|
+
* @param taken - whether a name is taken
|
|
794
|
+
* @param base - the preferred name
|
|
795
|
+
* @returns the name
|
|
796
|
+
*/
|
|
797
|
+
function freeName(taken, base) {
|
|
798
|
+
let name = base;
|
|
799
|
+
let k = 2;
|
|
800
|
+
while (taken(name)) {
|
|
801
|
+
name = `${base}#${String(k)}`;
|
|
802
|
+
k++;
|
|
803
|
+
}
|
|
804
|
+
return name;
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Whether a property's values are text: an empty text draws what no text draws, so a format that holds no "unset"
|
|
808
|
+
* (CyCSV) reads one back as "".
|
|
809
|
+
* @param target - nodes or edges
|
|
810
|
+
* @param property - the property
|
|
811
|
+
* @returns true for text
|
|
812
|
+
*/
|
|
813
|
+
function textProperty(target, property) {
|
|
814
|
+
return STYLE_PROPERTIES[target].get(property) === "text";
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* The elements whose native value differs from what the rules give: another program edited them. Where the rules
|
|
818
|
+
* give no value, the program's own drawing of an unset property, and an empty text, are no edit.
|
|
819
|
+
* @param values - the native values
|
|
820
|
+
* @param resolved - what the rules give
|
|
821
|
+
* @param unset - what the writing program draws for the unset property, or undefined
|
|
822
|
+
* @param text - whether the property is text
|
|
823
|
+
* @returns the edited values, null where an element is not edited; null when none is
|
|
824
|
+
*/
|
|
825
|
+
function editedValues(values, resolved, unset, text) {
|
|
826
|
+
const empty = text ? "" : undefined;
|
|
827
|
+
let exceptions = null;
|
|
828
|
+
for (let i = 0; i < resolved.length; i++) {
|
|
829
|
+
const t = values[i] ?? null;
|
|
830
|
+
const unchanged = resolved[i] === null && (t === unset || t === empty);
|
|
831
|
+
if (t !== null && !within(t, resolved[i]) && !unchanged) {
|
|
832
|
+
exceptions ?? (exceptions = new Array(resolved.length).fill(null));
|
|
833
|
+
exceptions[i] = t;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
return exceptions;
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* The passthrough mappings of the elements whose native value differs from what the rules give, each over a new
|
|
840
|
+
* exceptions column.
|
|
841
|
+
* @param own - the native per-element values by property
|
|
842
|
+
* @param rules - the block's rules
|
|
843
|
+
* @param target - nodes or edges
|
|
844
|
+
* @param src - what the rules read
|
|
845
|
+
* @param columns - the target's style columns, added to
|
|
846
|
+
* @param unsetOf - what the writing program draws for an unset property
|
|
847
|
+
* @returns the mappings by property, empty when nothing was edited
|
|
848
|
+
*/
|
|
849
|
+
function exceptionMappings(own, rules, target, src, columns, unsetOf) {
|
|
850
|
+
const map = Object.create(null);
|
|
851
|
+
// in one order whatever order the reader found the properties in, so a file written again is the same
|
|
852
|
+
for (const [property, values] of Object.entries(own).sort(([a], [b]) => (a < b ? -1 : 1))) {
|
|
853
|
+
if (values === undefined) {
|
|
854
|
+
continue;
|
|
855
|
+
}
|
|
856
|
+
const resolved = resolveRules(rules, target, property, src);
|
|
857
|
+
const exceptions = editedValues(values, resolved, unsetOf(property), textProperty(target, property));
|
|
858
|
+
if (exceptions !== null) {
|
|
859
|
+
const key = freeName((k) => columns.has(k), `exceptions.${property}`);
|
|
860
|
+
columns.set(key, exceptions);
|
|
861
|
+
map[property] = { kind: "passthrough", by: { style: key } };
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
return map;
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* The styles a valid block describes, read against the graph it was imported into. The block's rules are the
|
|
868
|
+
* file's declared rules and read the tagged per-element values. Where the file's own native values are given, they
|
|
869
|
+
* are the truth: an element whose value differs from what the rules give (another program edited it) is written
|
|
870
|
+
* into one exceptions rule on top, so the styles stay exact and, with no edit, are the block's rules unchanged.
|
|
871
|
+
* @param block - a block `parseStyleBlock()` accepted for this graph
|
|
872
|
+
* @param snapshot - the graph
|
|
873
|
+
* @param format - the format the file was read as
|
|
874
|
+
* @param truth - the native per-element values per target and property, when the format has any
|
|
875
|
+
* @param notes - notes to carry (the reader's own)
|
|
876
|
+
* @param tool - the program whose drawing the native values describe: where the rules give an element no value and
|
|
877
|
+
* the file holds only what that program draws for an unset property (a font written with "plain" style), it is not
|
|
878
|
+
* an edit
|
|
879
|
+
* @param opacityInColor - whether the format writes a fill's and an edge's opacity as its color's alpha: a native
|
|
880
|
+
* color with no native opacity then states opacity 1 where the rules give a translucent one
|
|
881
|
+
* @returns the styles, or null when a style column the rules read is missing from the file
|
|
882
|
+
* @category Styles
|
|
883
|
+
*/
|
|
884
|
+
export function blockStyles(block, snapshot, format, truth = {}, notes = [], tool = null, opacityInColor = false) {
|
|
885
|
+
const node = blockColumns(block, snapshot, "node");
|
|
886
|
+
const edge = blockColumns(block, snapshot, "edge");
|
|
887
|
+
if (node === null || edge === null) {
|
|
888
|
+
return null;
|
|
889
|
+
}
|
|
890
|
+
const columns = { node, edge };
|
|
891
|
+
asBooleans(block, columns);
|
|
892
|
+
const features = { node: featuresOf(snapshot, "node"), edge: featuresOf(snapshot, "edge") };
|
|
893
|
+
// a data column the file holds under another name is read there
|
|
894
|
+
const moved = { node: movedColumns(block, snapshot, "node"), edge: movedColumns(block, snapshot, "edge") };
|
|
895
|
+
const blockRules = block.rules.map((r) => (moved[r.target].size === 0 ? r : renameData(r, moved[r.target])));
|
|
896
|
+
const rules = [...blockRules];
|
|
897
|
+
for (const target of TARGETS) {
|
|
898
|
+
const n = target === "node" ? snapshot.nodeCount : snapshot.edgeCount;
|
|
899
|
+
const src = refSource(target, n, columns[target], features[target], snapshot);
|
|
900
|
+
const own = opacityInColor ? opaqueColors(truth[target] ?? {}, target, blockRules, src, n) : truth[target];
|
|
901
|
+
const unsetOf = (property) => (tool === null ? null : toolDefaults(tool))?.[target]?.[property]?.value;
|
|
902
|
+
const map = exceptionMappings(own ?? {}, blockRules, target, src, columns[target], unsetOf);
|
|
903
|
+
if (Object.keys(map).length > 0) {
|
|
904
|
+
// the block's own rules may hold an exceptions rule already (a file graphty wrote from an edited one)
|
|
905
|
+
const id = freeName((x) => rules.some((r) => r.id === x), `${target}.exceptions`);
|
|
906
|
+
rules.push({
|
|
907
|
+
id,
|
|
908
|
+
target,
|
|
909
|
+
role: "exceptions",
|
|
910
|
+
origin: "inferred",
|
|
911
|
+
where: { all: true },
|
|
912
|
+
map,
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
return {
|
|
917
|
+
styles: {
|
|
918
|
+
version: 1,
|
|
919
|
+
source: { format, dialect: "graphty", tool: "graphty" },
|
|
920
|
+
units: block.units,
|
|
921
|
+
graph: block.graph,
|
|
922
|
+
rules,
|
|
923
|
+
notes,
|
|
924
|
+
},
|
|
925
|
+
columns,
|
|
926
|
+
features,
|
|
927
|
+
fingerprint: styleFingerprint(snapshot),
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
//# sourceMappingURL=block.js.map
|