@graphty/graph-io 0.3.42 → 0.3.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/approximations-3Q4TsdTh.js +40 -0
- package/dist/chunks/approximations-3Q4TsdTh.js.map +1 -0
- package/dist/chunks/block-JQiwViEt.js +2777 -0
- package/dist/chunks/block-JQiwViEt.js.map +1 -0
- package/dist/chunks/{choose-DvpbdRuz.js → choose-BemygfH8.js} +3 -2
- package/dist/chunks/{choose-DvpbdRuz.js.map → choose-BemygfH8.js.map} +1 -1
- package/dist/chunks/{constants-fT3E8JYY.js → constants-BFUR_CtU.js} +6 -2
- package/dist/chunks/constants-BFUR_CtU.js.map +1 -0
- package/dist/chunks/convert-BcQ8_jMo.js +59 -0
- package/dist/chunks/convert-BcQ8_jMo.js.map +1 -0
- package/dist/chunks/emit-DCwFLts5.js +3456 -0
- package/dist/chunks/emit-DCwFLts5.js.map +1 -0
- package/dist/chunks/{escape-B62ZGM_a.js → escape-B1rMftd9.js} +43 -20
- package/dist/chunks/escape-B1rMftd9.js.map +1 -0
- package/dist/chunks/{export-rKLeGQMo.js → export-D7IGzTG4.js} +196 -792
- package/dist/chunks/export-D7IGzTG4.js.map +1 -0
- package/dist/chunks/{exporter-BWwEuOPT.js → exporter-BtnqYuuj.js} +22 -12
- package/dist/chunks/exporter-BtnqYuuj.js.map +1 -0
- package/dist/chunks/{exporter-yLxKBvLE.js → exporter-ChPyhBOv.js} +4 -3
- package/dist/chunks/{exporter-yLxKBvLE.js.map → exporter-ChPyhBOv.js.map} +1 -1
- package/dist/chunks/{exporter-8hLNemFk.js → exporter-KEPxYUXD.js} +133 -74
- package/dist/chunks/exporter-KEPxYUXD.js.map +1 -0
- package/dist/chunks/{exporter-CpRyHZ3H.js → exporter-quPUCBiC.js} +1807 -288
- package/dist/chunks/exporter-quPUCBiC.js.map +1 -0
- package/dist/chunks/format-GDmO6m6Q.js +676 -0
- package/dist/chunks/format-GDmO6m6Q.js.map +1 -0
- package/dist/chunks/generic-BL06jrJf.js +1347 -0
- package/dist/chunks/generic-BL06jrJf.js.map +1 -0
- package/dist/chunks/{importer-WrGRZb0N.js → importer-B7r2owVf.js} +449 -102
- package/dist/chunks/importer-B7r2owVf.js.map +1 -0
- package/dist/chunks/{importer-Ht7LNg8L.js → importer-BFmOP96W.js} +116 -296
- package/dist/chunks/importer-BFmOP96W.js.map +1 -0
- package/dist/chunks/{importer-BbNb7eNg.js → importer-C2nzGhdV.js} +1390 -129
- package/dist/chunks/importer-C2nzGhdV.js.map +1 -0
- package/dist/chunks/{importer-Dz7tI8Sa.js → importer-CbX2_rNF.js} +617 -115
- package/dist/chunks/importer-CbX2_rNF.js.map +1 -0
- package/dist/chunks/{importer-D794XUTe.js → importer-CdzeN6X4.js} +31 -8
- package/dist/chunks/importer-CdzeN6X4.js.map +1 -0
- package/dist/chunks/{importer-xZ-3suY1.js → importer-ChKNC_GN.js} +791 -135
- package/dist/chunks/importer-ChKNC_GN.js.map +1 -0
- package/dist/chunks/{importer-C98dpSH4.js → importer-dwoYpSqb.js} +141 -82
- package/dist/chunks/importer-dwoYpSqb.js.map +1 -0
- package/dist/chunks/index-B9fdNpTA.js +4310 -0
- package/dist/chunks/index-B9fdNpTA.js.map +1 -0
- package/dist/chunks/{json-elements-DKSqpNW1.js → json-elements-C4FwgnH5.js} +123 -32
- package/dist/chunks/json-elements-C4FwgnH5.js.map +1 -0
- package/dist/chunks/lexicon-B-knUi-l.js +508 -0
- package/dist/chunks/lexicon-B-knUi-l.js.map +1 -0
- package/dist/chunks/{ontology-export-CtRXjg_i.js → ontology-export-BSpbY5FL.js} +3 -2
- package/dist/chunks/{ontology-export-CtRXjg_i.js.map → ontology-export-BSpbY5FL.js.map} +1 -1
- package/dist/chunks/{records-Cu4bxYOm.js → records-Nwz_rbNt.js} +2 -2
- package/dist/chunks/{records-Cu4bxYOm.js.map → records-Nwz_rbNt.js.map} +1 -1
- package/dist/chunks/styles-Brt9JMfs.js +690 -0
- package/dist/chunks/styles-Brt9JMfs.js.map +1 -0
- package/dist/chunks/styles-_N-C8S-U.js +2102 -0
- package/dist/chunks/styles-_N-C8S-U.js.map +1 -0
- package/dist/chunks/styles-yed-DAfcIkf7.js +842 -0
- package/dist/chunks/styles-yed-DAfcIkf7.js.map +1 -0
- package/dist/chunks/{text-DHOJXnED.js → text-CgzMqHQb.js} +2 -2
- package/dist/chunks/{text-DHOJXnED.js.map → text-CgzMqHQb.js.map} +1 -1
- package/dist/chunks/units-XMZFIFe1.js +19 -0
- package/dist/chunks/units-XMZFIFe1.js.map +1 -0
- package/dist/csv.js +5 -4
- package/dist/csv.js.map +1 -1
- package/dist/cx.js +1 -1
- package/dist/cx2.js +2 -2
- package/dist/cys.js +1 -1
- package/dist/dot.js +5 -2
- package/dist/dot.js.map +1 -1
- package/dist/gexf.js +295 -414
- package/dist/gexf.js.map +1 -1
- package/dist/gml.js +8 -3031
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +354 -240
- package/dist/graph-io.js.map +1 -1
- package/dist/graphml.js +4 -2
- package/dist/graphml.js.map +1 -1
- package/dist/json.js +1 -1
- package/dist/neo4j.js +4 -3
- package/dist/neo4j.js.map +1 -1
- package/dist/obo.js +1 -1
- package/dist/pajek.js +4 -2
- package/dist/positions.d.ts +1 -0
- package/dist/positions.js +427 -0
- package/dist/positions.js.map +1 -0
- package/dist/src/common/codes.d.ts +6 -0
- package/dist/src/common/codes.d.ts.map +1 -1
- package/dist/src/common/codes.js +6 -0
- package/dist/src/common/codes.js.map +1 -1
- package/dist/src/common/escape.d.ts.map +1 -1
- package/dist/src/common/escape.js +4 -2
- package/dist/src/common/escape.js.map +1 -1
- package/dist/src/common/export.d.ts +10 -0
- package/dist/src/common/export.d.ts.map +1 -1
- package/dist/src/common/export.js +123 -100
- package/dist/src/common/export.js.map +1 -1
- package/dist/src/common/input.d.ts.map +1 -1
- package/dist/src/common/input.js +8 -1
- package/dist/src/common/input.js.map +1 -1
- package/dist/src/common/json-elements.d.ts +12 -9
- package/dist/src/common/json-elements.d.ts.map +1 -1
- package/dist/src/common/json-elements.js +160 -37
- package/dist/src/common/json-elements.js.map +1 -1
- package/dist/src/common/notes.d.ts +42 -0
- package/dist/src/common/notes.d.ts.map +1 -0
- package/dist/src/common/notes.js +72 -0
- package/dist/src/common/notes.js.map +1 -0
- package/dist/src/common/report.d.ts +18 -0
- package/dist/src/common/report.d.ts.map +1 -1
- package/dist/src/common/report.js +36 -1
- package/dist/src/common/report.js.map +1 -1
- package/dist/src/common/units.d.ts +24 -0
- package/dist/src/common/units.d.ts.map +1 -0
- package/dist/src/common/units.js +26 -0
- package/dist/src/common/units.js.map +1 -0
- package/dist/src/common/xml.d.ts +18 -0
- package/dist/src/common/xml.d.ts.map +1 -1
- package/dist/src/common/xml.js +42 -5
- package/dist/src/common/xml.js.map +1 -1
- package/dist/src/formats/cx/exporter.d.ts +6 -0
- package/dist/src/formats/cx/exporter.d.ts.map +1 -1
- package/dist/src/formats/cx/exporter.js +71 -8
- package/dist/src/formats/cx/exporter.js.map +1 -1
- package/dist/src/formats/cx/importer.d.ts +5 -2
- package/dist/src/formats/cx/importer.d.ts.map +1 -1
- package/dist/src/formats/cx/importer.js +102 -72
- package/dist/src/formats/cx/importer.js.map +1 -1
- package/dist/src/formats/cx/styles.d.ts +102 -0
- package/dist/src/formats/cx/styles.d.ts.map +1 -0
- package/dist/src/formats/cx/styles.js +225 -0
- package/dist/src/formats/cx/styles.js.map +1 -0
- package/dist/src/formats/cx2/exporter.d.ts +5 -0
- package/dist/src/formats/cx2/exporter.d.ts.map +1 -1
- package/dist/src/formats/cx2/exporter.js +181 -71
- package/dist/src/formats/cx2/exporter.js.map +1 -1
- package/dist/src/formats/cx2/importer.d.ts +4 -1
- package/dist/src/formats/cx2/importer.d.ts.map +1 -1
- package/dist/src/formats/cx2/importer.js +19 -1
- package/dist/src/formats/cx2/importer.js.map +1 -1
- package/dist/src/formats/cx2/styles.d.ts +18 -0
- package/dist/src/formats/cx2/styles.d.ts.map +1 -0
- package/dist/src/formats/cx2/styles.js +24 -0
- package/dist/src/formats/cx2/styles.js.map +1 -0
- package/dist/src/formats/cys/constants.d.ts +2 -0
- package/dist/src/formats/cys/constants.d.ts.map +1 -1
- package/dist/src/formats/cys/constants.js +2 -0
- package/dist/src/formats/cys/constants.js.map +1 -1
- package/dist/src/formats/cys/exporter.d.ts +6 -2
- package/dist/src/formats/cys/exporter.d.ts.map +1 -1
- package/dist/src/formats/cys/exporter.js +215 -53
- package/dist/src/formats/cys/exporter.js.map +1 -1
- package/dist/src/formats/cys/importer.d.ts +2 -1
- package/dist/src/formats/cys/importer.d.ts.map +1 -1
- package/dist/src/formats/cys/importer.js +119 -6
- package/dist/src/formats/cys/importer.js.map +1 -1
- package/dist/src/formats/cys/session.d.ts +2 -0
- package/dist/src/formats/cys/session.d.ts.map +1 -1
- package/dist/src/formats/cys/session.js +5 -0
- package/dist/src/formats/cys/session.js.map +1 -1
- package/dist/src/formats/cys/styles.d.ts +38 -0
- package/dist/src/formats/cys/styles.d.ts.map +1 -0
- package/dist/src/formats/cys/styles.js +213 -0
- package/dist/src/formats/cys/styles.js.map +1 -0
- package/dist/src/formats/cys/tables.d.ts +8 -3
- package/dist/src/formats/cys/tables.d.ts.map +1 -1
- package/dist/src/formats/cys/tables.js +88 -34
- package/dist/src/formats/cys/tables.js.map +1 -1
- package/dist/src/formats/dot/exporter.d.ts +2 -0
- package/dist/src/formats/dot/exporter.d.ts.map +1 -1
- package/dist/src/formats/dot/exporter.js +195 -81
- package/dist/src/formats/dot/exporter.js.map +1 -1
- package/dist/src/formats/dot/importer.d.ts.map +1 -1
- package/dist/src/formats/dot/importer.js +100 -20
- package/dist/src/formats/dot/importer.js.map +1 -1
- package/dist/src/formats/dot/index.d.ts +1 -0
- package/dist/src/formats/dot/index.d.ts.map +1 -1
- package/dist/src/formats/dot/index.js +1 -0
- package/dist/src/formats/dot/index.js.map +1 -1
- package/dist/src/formats/dot/positions.d.ts +14 -0
- package/dist/src/formats/dot/positions.d.ts.map +1 -0
- package/dist/src/formats/dot/positions.js +70 -0
- package/dist/src/formats/dot/positions.js.map +1 -0
- package/dist/src/formats/dot/styles.d.ts +82 -0
- package/dist/src/formats/dot/styles.d.ts.map +1 -0
- package/dist/src/formats/dot/styles.js +1484 -0
- package/dist/src/formats/dot/styles.js.map +1 -0
- package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
- package/dist/src/formats/gexf/exporter.js +23 -7
- package/dist/src/formats/gexf/exporter.js.map +1 -1
- package/dist/src/formats/gexf/importer.d.ts +8 -1
- package/dist/src/formats/gexf/importer.d.ts.map +1 -1
- package/dist/src/formats/gexf/importer.js +251 -131
- package/dist/src/formats/gexf/importer.js.map +1 -1
- package/dist/src/formats/gexf/index.d.ts +8 -0
- package/dist/src/formats/gexf/index.d.ts.map +1 -1
- package/dist/src/formats/gexf/index.js +10 -2
- package/dist/src/formats/gexf/index.js.map +1 -1
- package/dist/src/formats/gexf/schema.d.ts +5 -0
- package/dist/src/formats/gexf/schema.d.ts.map +1 -1
- package/dist/src/formats/gexf/schema.js +5 -0
- package/dist/src/formats/gexf/schema.js.map +1 -1
- package/dist/src/formats/gexf/styles.d.ts +74 -0
- package/dist/src/formats/gexf/styles.d.ts.map +1 -0
- package/dist/src/formats/gexf/styles.js +604 -0
- package/dist/src/formats/gexf/styles.js.map +1 -0
- package/dist/src/formats/gml/exporter.d.ts +1 -5
- package/dist/src/formats/gml/exporter.d.ts.map +1 -1
- package/dist/src/formats/gml/exporter.js +19 -8
- package/dist/src/formats/gml/exporter.js.map +1 -1
- package/dist/src/formats/gml/importer.d.ts.map +1 -1
- package/dist/src/formats/gml/importer.js +4 -0
- package/dist/src/formats/gml/importer.js.map +1 -1
- package/dist/src/formats/gml/index.d.ts +2 -1
- package/dist/src/formats/gml/index.d.ts.map +1 -1
- package/dist/src/formats/gml/index.js +2 -1
- package/dist/src/formats/gml/index.js.map +1 -1
- package/dist/src/formats/gml/positions.d.ts +14 -0
- package/dist/src/formats/gml/positions.d.ts.map +1 -0
- package/dist/src/formats/gml/positions.js +46 -0
- package/dist/src/formats/gml/positions.js.map +1 -0
- package/dist/src/formats/gml/styles.d.ts +59 -0
- package/dist/src/formats/gml/styles.d.ts.map +1 -0
- package/dist/src/formats/gml/styles.js +1056 -0
- package/dist/src/formats/gml/styles.js.map +1 -0
- package/dist/src/formats/gml/syntax.d.ts +11 -0
- package/dist/src/formats/gml/syntax.d.ts.map +1 -1
- package/dist/src/formats/gml/syntax.js +151 -62
- package/dist/src/formats/gml/syntax.js.map +1 -1
- package/dist/src/formats/graphml/constants.d.ts +4 -0
- package/dist/src/formats/graphml/constants.d.ts.map +1 -1
- package/dist/src/formats/graphml/constants.js +5 -1
- package/dist/src/formats/graphml/constants.js.map +1 -1
- package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
- package/dist/src/formats/graphml/exporter.js +133 -65
- package/dist/src/formats/graphml/exporter.js.map +1 -1
- package/dist/src/formats/graphml/importer.d.ts +4 -1
- package/dist/src/formats/graphml/importer.d.ts.map +1 -1
- package/dist/src/formats/graphml/importer.js +100 -44
- package/dist/src/formats/graphml/importer.js.map +1 -1
- package/dist/src/formats/graphml/index.d.ts +1 -0
- package/dist/src/formats/graphml/index.d.ts.map +1 -1
- package/dist/src/formats/graphml/index.js +1 -0
- package/dist/src/formats/graphml/index.js.map +1 -1
- package/dist/src/formats/graphml/styles-plain.d.ts +19 -0
- package/dist/src/formats/graphml/styles-plain.d.ts.map +1 -0
- package/dist/src/formats/graphml/styles-plain.js +187 -0
- package/dist/src/formats/graphml/styles-plain.js.map +1 -0
- package/dist/src/formats/graphml/styles-yed.d.ts +179 -0
- package/dist/src/formats/graphml/styles-yed.d.ts.map +1 -0
- package/dist/src/formats/graphml/styles-yed.js +1086 -0
- package/dist/src/formats/graphml/styles-yed.js.map +1 -0
- package/dist/src/formats/graphml/styles-yfiles3.d.ts +19 -0
- package/dist/src/formats/graphml/styles-yfiles3.d.ts.map +1 -0
- package/dist/src/formats/graphml/styles-yfiles3.js +508 -0
- package/dist/src/formats/graphml/styles-yfiles3.js.map +1 -0
- package/dist/src/formats/graphml/tree.d.ts.map +1 -1
- package/dist/src/formats/graphml/tree.js +34 -19
- package/dist/src/formats/graphml/tree.js.map +1 -1
- package/dist/src/formats/graphml/yfiles.d.ts +16 -2
- package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
- package/dist/src/formats/graphml/yfiles.js +83 -12
- package/dist/src/formats/graphml/yfiles.js.map +1 -1
- package/dist/src/formats/json/exporter.d.ts +5 -0
- package/dist/src/formats/json/exporter.d.ts.map +1 -1
- package/dist/src/formats/json/exporter.js +68 -25
- package/dist/src/formats/json/exporter.js.map +1 -1
- package/dist/src/formats/json/importer.d.ts +22 -3
- package/dist/src/formats/json/importer.d.ts.map +1 -1
- package/dist/src/formats/json/importer.js +441 -265
- package/dist/src/formats/json/importer.js.map +1 -1
- package/dist/src/formats/json/positions.d.ts +16 -0
- package/dist/src/formats/json/positions.d.ts.map +1 -0
- package/dist/src/formats/json/positions.js +44 -0
- package/dist/src/formats/json/positions.js.map +1 -0
- package/dist/src/formats/json/styles.d.ts +102 -0
- package/dist/src/formats/json/styles.d.ts.map +1 -0
- package/dist/src/formats/json/styles.js +1753 -0
- package/dist/src/formats/json/styles.js.map +1 -0
- package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
- package/dist/src/formats/neo4j/exporter.js +2 -1
- package/dist/src/formats/neo4j/exporter.js.map +1 -1
- package/dist/src/formats/pajek/exporter.d.ts +2 -0
- package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
- package/dist/src/formats/pajek/exporter.js +142 -76
- package/dist/src/formats/pajek/exporter.js.map +1 -1
- package/dist/src/formats/pajek/importer.d.ts +4 -0
- package/dist/src/formats/pajek/importer.d.ts.map +1 -1
- package/dist/src/formats/pajek/importer.js +60 -6
- package/dist/src/formats/pajek/importer.js.map +1 -1
- package/dist/src/formats/pajek/index.d.ts +2 -0
- package/dist/src/formats/pajek/index.d.ts.map +1 -1
- package/dist/src/formats/pajek/index.js +2 -0
- package/dist/src/formats/pajek/index.js.map +1 -1
- package/dist/src/formats/pajek/styles.d.ts +50 -0
- package/dist/src/formats/pajek/styles.d.ts.map +1 -0
- package/dist/src/formats/pajek/styles.js +569 -0
- package/dist/src/formats/pajek/styles.js.map +1 -0
- package/dist/src/formats/pajek/syntax.d.ts +6 -0
- package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
- package/dist/src/formats/pajek/syntax.js +6 -0
- package/dist/src/formats/pajek/syntax.js.map +1 -1
- package/dist/src/formats/xgmml/columns.d.ts.map +1 -1
- package/dist/src/formats/xgmml/columns.js +34 -9
- package/dist/src/formats/xgmml/columns.js.map +1 -1
- package/dist/src/formats/xgmml/constants.d.ts +2 -0
- package/dist/src/formats/xgmml/constants.d.ts.map +1 -1
- package/dist/src/formats/xgmml/constants.js +3 -1
- package/dist/src/formats/xgmml/constants.js.map +1 -1
- package/dist/src/formats/xgmml/document.d.ts +12 -8
- package/dist/src/formats/xgmml/document.d.ts.map +1 -1
- package/dist/src/formats/xgmml/document.js +56 -13
- package/dist/src/formats/xgmml/document.js.map +1 -1
- package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
- package/dist/src/formats/xgmml/emit.js +12 -6
- package/dist/src/formats/xgmml/emit.js.map +1 -1
- package/dist/src/formats/xgmml/exporter.d.ts +3 -1
- package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
- package/dist/src/formats/xgmml/exporter.js +22 -9
- package/dist/src/formats/xgmml/exporter.js.map +1 -1
- package/dist/src/formats/xgmml/importer.d.ts +2 -1
- package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
- package/dist/src/formats/xgmml/importer.js +31 -24
- package/dist/src/formats/xgmml/importer.js.map +1 -1
- package/dist/src/formats/xgmml/styles.d.ts +104 -0
- package/dist/src/formats/xgmml/styles.d.ts.map +1 -0
- package/dist/src/formats/xgmml/styles.js +310 -0
- package/dist/src/formats/xgmml/styles.js.map +1 -0
- package/dist/src/index.d.ts +9 -7
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +7 -7
- package/dist/src/index.js.map +1 -1
- package/dist/src/positions/codes.d.ts +31 -0
- package/dist/src/positions/codes.d.ts.map +1 -0
- package/dist/src/positions/codes.js +26 -0
- package/dist/src/positions/codes.js.map +1 -0
- package/dist/src/positions/convert.d.ts +58 -0
- package/dist/src/positions/convert.d.ts.map +1 -0
- package/dist/src/positions/convert.js +107 -0
- package/dist/src/positions/convert.js.map +1 -0
- package/dist/src/positions/extract.d.ts +27 -0
- package/dist/src/positions/extract.d.ts.map +1 -0
- package/dist/src/positions/extract.js +526 -0
- package/dist/src/positions/extract.js.map +1 -0
- package/dist/src/positions/index.d.ts +10 -0
- package/dist/src/positions/index.d.ts.map +1 -0
- package/dist/src/positions/index.js +9 -0
- package/dist/src/positions/index.js.map +1 -0
- package/dist/src/positions/types.d.ts +208 -0
- package/dist/src/positions/types.d.ts.map +1 -0
- package/dist/src/positions/types.js +10 -0
- package/dist/src/positions/types.js.map +1 -0
- package/dist/src/registry.d.ts +30 -0
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +130 -9
- package/dist/src/registry.js.map +1 -1
- package/dist/src/styles/annotations.d.ts +132 -0
- package/dist/src/styles/annotations.d.ts.map +1 -0
- package/dist/src/styles/annotations.js +320 -0
- package/dist/src/styles/annotations.js.map +1 -0
- package/dist/src/styles/budget.d.ts +45 -0
- package/dist/src/styles/budget.d.ts.map +1 -0
- package/dist/src/styles/budget.js +58 -0
- package/dist/src/styles/budget.js.map +1 -0
- package/dist/src/styles/canon/bends.d.ts +32 -0
- package/dist/src/styles/canon/bends.d.ts.map +1 -0
- package/dist/src/styles/canon/bends.js +74 -0
- package/dist/src/styles/canon/bends.js.map +1 -0
- package/dist/src/styles/canon/color-tables.d.ts +22 -0
- package/dist/src/styles/canon/color-tables.d.ts.map +1 -0
- package/dist/src/styles/canon/color-tables.js +369 -0
- package/dist/src/styles/canon/color-tables.js.map +1 -0
- package/dist/src/styles/canon/color.d.ts +66 -0
- package/dist/src/styles/canon/color.d.ts.map +1 -0
- package/dist/src/styles/canon/color.js +548 -0
- package/dist/src/styles/canon/color.js.map +1 -0
- package/dist/src/styles/canon/enums.d.ts +25 -0
- package/dist/src/styles/canon/enums.d.ts.map +1 -0
- package/dist/src/styles/canon/enums.js +187 -0
- package/dist/src/styles/canon/enums.js.map +1 -0
- package/dist/src/styles/canon/graphviz.d.ts +48 -0
- package/dist/src/styles/canon/graphviz.d.ts.map +1 -0
- package/dist/src/styles/canon/graphviz.js +160 -0
- package/dist/src/styles/canon/graphviz.js.map +1 -0
- package/dist/src/styles/canon/index.d.ts +13 -0
- package/dist/src/styles/canon/index.d.ts.map +1 -0
- package/dist/src/styles/canon/index.js +13 -0
- package/dist/src/styles/canon/index.js.map +1 -0
- package/dist/src/styles/canon/number.d.ts +59 -0
- package/dist/src/styles/canon/number.d.ts.map +1 -0
- package/dist/src/styles/canon/number.js +142 -0
- package/dist/src/styles/canon/number.js.map +1 -0
- package/dist/src/styles/canon/site.d.ts +51 -0
- package/dist/src/styles/canon/site.d.ts.map +1 -0
- package/dist/src/styles/canon/site.js +63 -0
- package/dist/src/styles/canon/site.js.map +1 -0
- package/dist/src/styles/canon/text.d.ts +61 -0
- package/dist/src/styles/canon/text.d.ts.map +1 -0
- package/dist/src/styles/canon/text.js +199 -0
- package/dist/src/styles/canon/text.js.map +1 -0
- package/dist/src/styles/codes.d.ts +95 -0
- package/dist/src/styles/codes.d.ts.map +1 -0
- package/dist/src/styles/codes.js +97 -0
- package/dist/src/styles/codes.js.map +1 -0
- package/dist/src/styles/cyjs/cascade.d.ts +134 -0
- package/dist/src/styles/cyjs/cascade.d.ts.map +1 -0
- package/dist/src/styles/cyjs/cascade.js +2252 -0
- package/dist/src/styles/cyjs/cascade.js.map +1 -0
- package/dist/src/styles/cyjs/defaults-table.d.ts +25 -0
- package/dist/src/styles/cyjs/defaults-table.d.ts.map +1 -0
- package/dist/src/styles/cyjs/defaults-table.js +76 -0
- package/dist/src/styles/cyjs/defaults-table.js.map +1 -0
- package/dist/src/styles/cyjs/emit.d.ts +82 -0
- package/dist/src/styles/cyjs/emit.d.ts.map +1 -0
- package/dist/src/styles/cyjs/emit.js +790 -0
- package/dist/src/styles/cyjs/emit.js.map +1 -0
- package/dist/src/styles/cyjs/index.d.ts +13 -0
- package/dist/src/styles/cyjs/index.d.ts.map +1 -0
- package/dist/src/styles/cyjs/index.js +13 -0
- package/dist/src/styles/cyjs/index.js.map +1 -0
- package/dist/src/styles/cyjs/live.d.ts +46 -0
- package/dist/src/styles/cyjs/live.d.ts.map +1 -0
- package/dist/src/styles/cyjs/live.js +108 -0
- package/dist/src/styles/cyjs/live.js.map +1 -0
- package/dist/src/styles/cyjs/mappers.d.ts +147 -0
- package/dist/src/styles/cyjs/mappers.d.ts.map +1 -0
- package/dist/src/styles/cyjs/mappers.js +744 -0
- package/dist/src/styles/cyjs/mappers.js.map +1 -0
- package/dist/src/styles/cyjs/selector.d.ts +113 -0
- package/dist/src/styles/cyjs/selector.d.ts.map +1 -0
- package/dist/src/styles/cyjs/selector.js +611 -0
- package/dist/src/styles/cyjs/selector.js.map +1 -0
- package/dist/src/styles/cyjs/stylesheet-text.d.ts +37 -0
- package/dist/src/styles/cyjs/stylesheet-text.d.ts.map +1 -0
- package/dist/src/styles/cyjs/stylesheet-text.js +181 -0
- package/dist/src/styles/cyjs/stylesheet-text.js.map +1 -0
- package/dist/src/styles/cytoscape/emit.d.ts +125 -0
- package/dist/src/styles/cytoscape/emit.d.ts.map +1 -0
- package/dist/src/styles/cytoscape/emit.js +1025 -0
- package/dist/src/styles/cytoscape/emit.js.map +1 -0
- package/dist/src/styles/cytoscape/index.d.ts +10 -0
- package/dist/src/styles/cytoscape/index.d.ts.map +1 -0
- package/dist/src/styles/cytoscape/index.js +10 -0
- package/dist/src/styles/cytoscape/index.js.map +1 -0
- package/dist/src/styles/cytoscape/lexicon.d.ts +49 -0
- package/dist/src/styles/cytoscape/lexicon.d.ts.map +1 -0
- package/dist/src/styles/cytoscape/lexicon.js +603 -0
- package/dist/src/styles/cytoscape/lexicon.js.map +1 -0
- package/dist/src/styles/cytoscape/mappings.d.ts +171 -0
- package/dist/src/styles/cytoscape/mappings.d.ts.map +1 -0
- package/dist/src/styles/cytoscape/mappings.js +460 -0
- package/dist/src/styles/cytoscape/mappings.js.map +1 -0
- package/dist/src/styles/cytoscape/resolve.d.ts +137 -0
- package/dist/src/styles/cytoscape/resolve.d.ts.map +1 -0
- package/dist/src/styles/cytoscape/resolve.js +381 -0
- package/dist/src/styles/cytoscape/resolve.js.map +1 -0
- package/dist/src/styles/cytoscape/translate.d.ts +50 -0
- package/dist/src/styles/cytoscape/translate.d.ts.map +1 -0
- package/dist/src/styles/cytoscape/translate.js +156 -0
- package/dist/src/styles/cytoscape/translate.js.map +1 -0
- package/dist/src/styles/defaults.d.ts +90 -0
- package/dist/src/styles/defaults.d.ts.map +1 -0
- package/dist/src/styles/defaults.js +414 -0
- package/dist/src/styles/defaults.js.map +1 -0
- package/dist/src/styles/index.d.ts +15 -0
- package/dist/src/styles/index.d.ts.map +1 -0
- package/dist/src/styles/index.js +14 -0
- package/dist/src/styles/index.js.map +1 -0
- package/dist/src/styles/internal.d.ts +17 -0
- package/dist/src/styles/internal.d.ts.map +1 -0
- package/dist/src/styles/internal.js +16 -0
- package/dist/src/styles/internal.js.map +1 -0
- package/dist/src/styles/io/approximations.d.ts +24 -0
- package/dist/src/styles/io/approximations.d.ts.map +1 -0
- package/dist/src/styles/io/approximations.js +51 -0
- package/dist/src/styles/io/approximations.js.map +1 -0
- package/dist/src/styles/io/block.d.ts +166 -0
- package/dist/src/styles/io/block.d.ts.map +1 -0
- package/dist/src/styles/io/block.js +930 -0
- package/dist/src/styles/io/block.js.map +1 -0
- package/dist/src/styles/io/generic.d.ts +88 -0
- package/dist/src/styles/io/generic.d.ts.map +1 -0
- package/dist/src/styles/io/generic.js +516 -0
- package/dist/src/styles/io/generic.js.map +1 -0
- package/dist/src/styles/io/index.d.ts +8 -0
- package/dist/src/styles/io/index.d.ts.map +1 -0
- package/dist/src/styles/io/index.js +7 -0
- package/dist/src/styles/io/index.js.map +1 -0
- package/dist/src/styles/io/writer.d.ts +80 -0
- package/dist/src/styles/io/writer.d.ts.map +1 -0
- package/dist/src/styles/io/writer.js +596 -0
- package/dist/src/styles/io/writer.js.map +1 -0
- package/dist/src/styles/notes.d.ts +47 -0
- package/dist/src/styles/notes.d.ts.map +1 -0
- package/dist/src/styles/notes.js +140 -0
- package/dist/src/styles/notes.js.map +1 -0
- package/dist/src/styles/plan/classes.d.ts +31 -0
- package/dist/src/styles/plan/classes.d.ts.map +1 -0
- package/dist/src/styles/plan/classes.js +139 -0
- package/dist/src/styles/plan/classes.js.map +1 -0
- package/dist/src/styles/plan/continuous.d.ts +32 -0
- package/dist/src/styles/plan/continuous.d.ts.map +1 -0
- package/dist/src/styles/plan/continuous.js +165 -0
- package/dist/src/styles/plan/continuous.js.map +1 -0
- package/dist/src/styles/plan/discrete.d.ts +39 -0
- package/dist/src/styles/plan/discrete.d.ts.map +1 -0
- package/dist/src/styles/plan/discrete.js +127 -0
- package/dist/src/styles/plan/discrete.js.map +1 -0
- package/dist/src/styles/plan/families.d.ts +31 -0
- package/dist/src/styles/plan/families.d.ts.map +1 -0
- package/dist/src/styles/plan/families.js +95 -0
- package/dist/src/styles/plan/families.js.map +1 -0
- package/dist/src/styles/plan/features.d.ts +58 -0
- package/dist/src/styles/plan/features.d.ts.map +1 -0
- package/dist/src/styles/plan/features.js +185 -0
- package/dist/src/styles/plan/features.js.map +1 -0
- package/dist/src/styles/plan/index.d.ts +7 -0
- package/dist/src/styles/plan/index.d.ts.map +1 -0
- package/dist/src/styles/plan/index.js +7 -0
- package/dist/src/styles/plan/index.js.map +1 -0
- package/dist/src/styles/plan/plan.d.ts +71 -0
- package/dist/src/styles/plan/plan.d.ts.map +1 -0
- package/dist/src/styles/plan/plan.js +893 -0
- package/dist/src/styles/plan/plan.js.map +1 -0
- package/dist/src/styles/plan/resolve.d.ts +137 -0
- package/dist/src/styles/plan/resolve.d.ts.map +1 -0
- package/dist/src/styles/plan/resolve.js +587 -0
- package/dist/src/styles/plan/resolve.js.map +1 -0
- package/dist/src/styles/types.d.ts +702 -0
- package/dist/src/styles/types.d.ts.map +1 -0
- package/dist/src/styles/types.js +10 -0
- package/dist/src/styles/types.js.map +1 -0
- package/dist/src/styles/vocabulary.d.ts +41 -0
- package/dist/src/styles/vocabulary.d.ts.map +1 -0
- package/dist/src/styles/vocabulary.js +140 -0
- package/dist/src/styles/vocabulary.js.map +1 -0
- package/dist/src/types.d.ts +64 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/styles.d.ts +1 -0
- package/dist/styles.js +322 -0
- package/dist/styles.js.map +1 -0
- package/dist/xgmml.js +5 -4
- package/dist/xgmml.js.map +1 -1
- package/package.json +13 -2
- package/src/common/codes.ts +7 -0
- package/src/common/escape.ts +5 -2
- package/src/common/export.ts +179 -140
- package/src/common/input.ts +8 -4
- package/src/common/json-elements.ts +169 -38
- package/src/common/notes.ts +94 -0
- package/src/common/report.ts +41 -1
- package/src/common/units.ts +42 -0
- package/src/common/xml.ts +45 -5
- package/src/formats/cx/exporter.ts +95 -11
- package/src/formats/cx/importer.ts +126 -90
- package/src/formats/cx/styles.ts +304 -0
- package/src/formats/cx2/exporter.ts +234 -77
- package/src/formats/cx2/importer.ts +19 -1
- package/src/formats/cx2/styles.ts +29 -0
- package/src/formats/cys/constants.ts +3 -0
- package/src/formats/cys/exporter.ts +246 -60
- package/src/formats/cys/importer.ts +125 -9
- package/src/formats/cys/session.ts +6 -0
- package/src/formats/cys/styles.ts +254 -0
- package/src/formats/cys/tables.ts +117 -48
- package/src/formats/dot/exporter.ts +262 -126
- package/src/formats/dot/importer.ts +111 -20
- package/src/formats/dot/index.ts +1 -0
- package/src/formats/dot/positions.ts +77 -0
- package/src/formats/dot/styles.ts +1741 -0
- package/src/formats/gexf/exporter.ts +30 -13
- package/src/formats/gexf/importer.ts +308 -158
- package/src/formats/gexf/index.ts +10 -0
- package/src/formats/gexf/schema.ts +5 -0
- package/src/formats/gexf/styles.ts +719 -0
- package/src/formats/gml/exporter.ts +33 -14
- package/src/formats/gml/importer.ts +4 -0
- package/src/formats/gml/index.ts +2 -1
- package/src/formats/gml/positions.ts +52 -0
- package/src/formats/gml/styles.ts +1248 -0
- package/src/formats/gml/syntax.ts +173 -62
- package/src/formats/graphml/constants.ts +5 -0
- package/src/formats/graphml/exporter.ts +163 -71
- package/src/formats/graphml/importer.ts +119 -45
- package/src/formats/graphml/index.ts +1 -0
- package/src/formats/graphml/styles-plain.ts +236 -0
- package/src/formats/graphml/styles-yed.ts +1221 -0
- package/src/formats/graphml/styles-yfiles3.ts +573 -0
- package/src/formats/graphml/tree.ts +36 -20
- package/src/formats/graphml/yfiles.ts +89 -13
- package/src/formats/json/exporter.ts +76 -26
- package/src/formats/json/importer.ts +543 -323
- package/src/formats/json/positions.ts +50 -0
- package/src/formats/json/styles.ts +2082 -0
- package/src/formats/neo4j/exporter.ts +2 -1
- package/src/formats/pajek/exporter.ts +195 -106
- package/src/formats/pajek/importer.ts +78 -9
- package/src/formats/pajek/index.ts +2 -0
- package/src/formats/pajek/styles.ts +685 -0
- package/src/formats/pajek/syntax.ts +7 -0
- package/src/formats/xgmml/columns.ts +39 -9
- package/src/formats/xgmml/constants.ts +3 -0
- package/src/formats/xgmml/document.ts +54 -12
- package/src/formats/xgmml/emit.ts +11 -6
- package/src/formats/xgmml/exporter.ts +32 -13
- package/src/formats/xgmml/importer.ts +43 -29
- package/src/formats/xgmml/styles.ts +400 -0
- package/src/index.ts +16 -0
- package/src/positions/codes.ts +32 -0
- package/src/positions/convert.ts +123 -0
- package/src/positions/extract.ts +619 -0
- package/src/positions/index.ts +23 -0
- package/src/positions/types.ts +221 -0
- package/src/registry.ts +179 -8
- package/src/styles/annotations.ts +478 -0
- package/src/styles/budget.ts +60 -0
- package/src/styles/canon/bends.ts +84 -0
- package/src/styles/canon/color-tables.ts +386 -0
- package/src/styles/canon/color.ts +624 -0
- package/src/styles/canon/enums.ts +211 -0
- package/src/styles/canon/graphviz.ts +189 -0
- package/src/styles/canon/index.ts +13 -0
- package/src/styles/canon/number.ts +152 -0
- package/src/styles/canon/site.ts +87 -0
- package/src/styles/canon/text.ts +221 -0
- package/src/styles/codes.ts +104 -0
- package/src/styles/cyjs/cascade.ts +2670 -0
- package/src/styles/cyjs/defaults-table.ts +82 -0
- package/src/styles/cyjs/emit.ts +951 -0
- package/src/styles/cyjs/index.ts +37 -0
- package/src/styles/cyjs/live.ts +147 -0
- package/src/styles/cyjs/mappers.ts +879 -0
- package/src/styles/cyjs/selector.ts +778 -0
- package/src/styles/cyjs/stylesheet-text.ts +214 -0
- package/src/styles/cytoscape/emit.ts +1264 -0
- package/src/styles/cytoscape/index.ts +40 -0
- package/src/styles/cytoscape/lexicon.ts +656 -0
- package/src/styles/cytoscape/mappings.ts +603 -0
- package/src/styles/cytoscape/resolve.ts +521 -0
- package/src/styles/cytoscape/translate.ts +237 -0
- package/src/styles/defaults.ts +504 -0
- package/src/styles/index.ts +57 -0
- package/src/styles/internal.ts +17 -0
- package/src/styles/io/approximations.ts +47 -0
- package/src/styles/io/block.ts +1138 -0
- package/src/styles/io/generic.ts +687 -0
- package/src/styles/io/index.ts +18 -0
- package/src/styles/io/writer.ts +745 -0
- package/src/styles/notes.ts +165 -0
- package/src/styles/plan/classes.ts +166 -0
- package/src/styles/plan/continuous.ts +218 -0
- package/src/styles/plan/discrete.ts +165 -0
- package/src/styles/plan/families.ts +115 -0
- package/src/styles/plan/features.ts +234 -0
- package/src/styles/plan/index.ts +7 -0
- package/src/styles/plan/plan.ts +1129 -0
- package/src/styles/plan/resolve.ts +685 -0
- package/src/styles/types.ts +814 -0
- package/src/styles/vocabulary.ts +172 -0
- package/src/types.ts +76 -1
- package/dist/chunks/constants-fT3E8JYY.js.map +0 -1
- package/dist/chunks/escape-B62ZGM_a.js.map +0 -1
- package/dist/chunks/export-rKLeGQMo.js.map +0 -1
- package/dist/chunks/exporter-8hLNemFk.js.map +0 -1
- package/dist/chunks/exporter-BWwEuOPT.js.map +0 -1
- package/dist/chunks/exporter-CpRyHZ3H.js.map +0 -1
- package/dist/chunks/importer-BbNb7eNg.js.map +0 -1
- package/dist/chunks/importer-C98dpSH4.js.map +0 -1
- package/dist/chunks/importer-D794XUTe.js.map +0 -1
- package/dist/chunks/importer-Dz7tI8Sa.js.map +0 -1
- package/dist/chunks/importer-Ht7LNg8L.js.map +0 -1
- package/dist/chunks/importer-WrGRZb0N.js.map +0 -1
- package/dist/chunks/importer-xZ-3suY1.js.map +0 -1
- package/dist/chunks/json-elements-DKSqpNW1.js.map +0 -1
|
@@ -36,14 +36,17 @@ import { AMBIGUOUS_GRAPH_NAME_CODE, BAD_VALUE_CODE, COLUMN_RENAMED_CODE, DANGLIN
|
|
|
36
36
|
import { DirectionResolver } from "../../common/direction.js";
|
|
37
37
|
import { ID_MERGED_CODE, IdCoercer } from "../../common/ids.js";
|
|
38
38
|
import { readText, throwIfAborted } from "../../common/input.js";
|
|
39
|
-
import { findDuplicateKeys, flipY, MAYBE_INEXACT_EXPONENT, MAYBE_UNSAFE_INTEGER, rewriteNumbers, } from "../../common/json-elements.js";
|
|
39
|
+
import { findDuplicateKeys, flipY, keysInTextOrder, MAYBE_INEXACT_EXPONENT, MAYBE_UNSAFE_INTEGER, rewriteNumbers, } from "../../common/json-elements.js";
|
|
40
40
|
import { chooseGraph, graphChosen, reportSinkOptions, reportUnusedOptions, resolveImportOptions, SINK_OPTION_CODE, } from "../../common/options.js";
|
|
41
41
|
import { agree, plural } from "../../common/plural.js";
|
|
42
42
|
import { ImportReportBuilder } from "../../common/report.js";
|
|
43
43
|
import { weightFromValue } from "../../common/weights.js";
|
|
44
44
|
import { headBytes, sniffJsonDialectHead } from "../../sniff.js";
|
|
45
|
+
import { STYLE_BLOCK_NAME } from "../../styles/io/block.js";
|
|
45
46
|
import { CLASSES_COLUMN, CYTOSCAPE_ELEMENT_KEYS, CYTOSCAPE_STRUCTURAL_KEYS, DIALECT_DEFAULT_DIRECTED, hasKey, isJsonImportDialect, isJsonObject, JSON_IMPORT_DIALECTS, META_KEY, NODE_LINK_SOURCE_KEYS, NODE_LINK_TARGET_KEYS, PARENT_COLUMN, POSITION_COLUMN, sniffJsonDialect, SUFFIX, } from "./dialect.js";
|
|
46
47
|
import { importObographs } from "./obographs.js";
|
|
48
|
+
import { jsonPositions } from "./positions.js";
|
|
49
|
+
import { jsonStyles } from "./styles.js";
|
|
47
50
|
/**
|
|
48
51
|
* The issue codes the JSON importer records, by name: the codes shared with
|
|
49
52
|
* the other importers and the JSON-specific ones. A key is the code without
|
|
@@ -218,12 +221,18 @@ const JGF_EDGE_KEYS = new Set([
|
|
|
218
221
|
]);
|
|
219
222
|
/** The JGF hyperedge keys that are not metadata. */
|
|
220
223
|
const JGF_HYPEREDGE_KEYS = new Set([...JGF_EDGE_KEYS, "nodes"]);
|
|
224
|
+
/** A key JavaScript orders as an array index: digits with no leading zero, below 2^32 - 1. */
|
|
225
|
+
const ARRAY_INDEX = /^(?:0|[1-9]\d{0,9})$/;
|
|
221
226
|
/** The JGF node keys that are not metadata. */
|
|
222
227
|
const JGF_NODE_KEYS = new Set(["label", "metadata"]);
|
|
223
228
|
/** The graphology node keys that are not attributes. */
|
|
224
229
|
const GRAPHOLOGY_NODE_KEYS = new Set(["key", "attributes"]);
|
|
225
230
|
/** The graphology edge keys that are not attributes. */
|
|
226
231
|
const GRAPHOLOGY_EDGE_KEYS = new Set(["key", "source", "target", "attributes", "undirected"]);
|
|
232
|
+
/** The structural keys of a node in Gephi's JSON export. */
|
|
233
|
+
const GEPHI_NODE_KEYS = new Set(["id", "attributes"]);
|
|
234
|
+
/** The structural keys of an edge in Gephi's JSON export. */
|
|
235
|
+
const GEPHI_EDGE_KEYS = new Set([...GRAPHOLOGY_EDGE_KEYS, "id"]);
|
|
227
236
|
/** The vis.js endpoint keys. */
|
|
228
237
|
const VIS_SOURCE_KEYS = Object.freeze(["from"]);
|
|
229
238
|
const VIS_TARGET_KEYS = Object.freeze(["to"]);
|
|
@@ -634,6 +643,8 @@ export class ImportContext {
|
|
|
634
643
|
* @param explicitDefaultDirected - whether the caller passed defaultDirected
|
|
635
644
|
*/
|
|
636
645
|
constructor(sink, report, options, json, explicitDefaultDirected) {
|
|
646
|
+
/** The document's text, for an order JSON.parse does not keep (a JGF nodes object's integer-like keys). */
|
|
647
|
+
this.text = "";
|
|
637
648
|
/** Nodes and edges pushed since the signal was last checked. */
|
|
638
649
|
this.elementsSinceCheck = 0;
|
|
639
650
|
/** The direction the file declares (or the default), set by setHeader(). */
|
|
@@ -643,6 +654,8 @@ export class ImportContext {
|
|
|
643
654
|
this.danglingCount = 0;
|
|
644
655
|
/** Set when the document has no node section: every node comes from an edge (E_MISSING_SECTION says so). */
|
|
645
656
|
this.nodesFromEdges = false;
|
|
657
|
+
/** What the dialect's reader keeps for the style reader (`report.keepForStyles()`), or null. */
|
|
658
|
+
this.styleSource = null;
|
|
646
659
|
/** Dangling endpoints whose id, as the other JSON type, is a node (`"1"` next to the node 1). */
|
|
647
660
|
this.nearMatches = [];
|
|
648
661
|
this.sink = sink;
|
|
@@ -790,6 +803,31 @@ export class ImportContext {
|
|
|
790
803
|
}
|
|
791
804
|
return edge;
|
|
792
805
|
}
|
|
806
|
+
/**
|
|
807
|
+
* A Cytoscape.js endpoint or parent id: Cytoscape.js holds every id as text, so an endpoint `0` names the node
|
|
808
|
+
* `"0"` and an endpoint `"0"` the node `0` when the file has no node of the endpoint's own type.
|
|
809
|
+
* @param raw - the JSON value
|
|
810
|
+
* @param element - the element name for issues
|
|
811
|
+
* @returns the id, or null when the value was reported
|
|
812
|
+
*/
|
|
813
|
+
textualId(raw, element) {
|
|
814
|
+
const id = this.coerceId(raw, element);
|
|
815
|
+
if (id === null || this.sink.indexOf(id) !== INVALID_INDEX) {
|
|
816
|
+
return id;
|
|
817
|
+
}
|
|
818
|
+
let other = null;
|
|
819
|
+
if (typeof raw === "number" && Number.isFinite(raw)) {
|
|
820
|
+
other = String(raw);
|
|
821
|
+
}
|
|
822
|
+
else if (typeof raw === "string" && /^-?\d+(?:\.\d+)?$/.test(raw)) {
|
|
823
|
+
other = Number(raw);
|
|
824
|
+
}
|
|
825
|
+
if (other === null) {
|
|
826
|
+
return id;
|
|
827
|
+
}
|
|
828
|
+
const alt = this.ids.value(other);
|
|
829
|
+
return this.sink.indexOf(alt) === INVALID_INDEX ? id : alt;
|
|
830
|
+
}
|
|
793
831
|
/**
|
|
794
832
|
* Count a placeholder node an edge endpoint created.
|
|
795
833
|
* @param id - the endpoint
|
|
@@ -953,10 +991,14 @@ export class ImportContext {
|
|
|
953
991
|
* @param record - the element record
|
|
954
992
|
* @param dict - the nested attribute dict
|
|
955
993
|
* @param structural - the element keys that are not attributes
|
|
956
|
-
* @param weightFrom - the weight key to skip in the dict, or null
|
|
957
994
|
* @param element - the element name for issues
|
|
995
|
+
* @param how - `weightFrom`: the weight key to skip in the dict; `plain`: write the element-level keys under their
|
|
996
|
+
* own names, not with the `#element` suffix
|
|
997
|
+
* @param how.weightFrom - the weight key to skip in the dict, or null (the default)
|
|
998
|
+
* @param how.plain - write the element-level keys under their own names (default false)
|
|
958
999
|
*/
|
|
959
|
-
writeNested(writer, row, record, dict, structural,
|
|
1000
|
+
writeNested(writer, row, record, dict, structural, element, how = {}) {
|
|
1001
|
+
const { weightFrom = null, plain = false } = how;
|
|
960
1002
|
for (const key of Object.keys(dict)) {
|
|
961
1003
|
if (key !== weightFrom) {
|
|
962
1004
|
writer.write(row, key, dict[key], SUFFIX.data, element);
|
|
@@ -964,7 +1006,7 @@ export class ImportContext {
|
|
|
964
1006
|
}
|
|
965
1007
|
for (const key of Object.keys(record)) {
|
|
966
1008
|
if (!structural.has(key)) {
|
|
967
|
-
writer.write(row, `${key}${SUFFIX.element}`, record[key], SUFFIX.data, element);
|
|
1009
|
+
writer.write(row, plain ? key : `${key}${SUFFIX.element}`, record[key], SUFFIX.data, element);
|
|
968
1010
|
}
|
|
969
1011
|
}
|
|
970
1012
|
}
|
|
@@ -1284,7 +1326,8 @@ function arraySection(value, what, report) {
|
|
|
1284
1326
|
if (!Array.isArray(value)) {
|
|
1285
1327
|
return report.fail(JSON_ISSUE.SHAPE, `${what} must be an array, found ${describe(value)}`, { element: what });
|
|
1286
1328
|
}
|
|
1287
|
-
|
|
1329
|
+
const items = value;
|
|
1330
|
+
return items;
|
|
1288
1331
|
}
|
|
1289
1332
|
/**
|
|
1290
1333
|
* A boolean flag with a default and a warning when it has another type.
|
|
@@ -1351,9 +1394,15 @@ function reportUnreadKeys(ctx, record, known, prefix) {
|
|
|
1351
1394
|
}
|
|
1352
1395
|
}
|
|
1353
1396
|
/** The keys of a vis.js document the reader reads. */
|
|
1354
|
-
const VIS_DOCUMENT_KEYS = new Set(["nodes", "edges"]);
|
|
1397
|
+
const VIS_DOCUMENT_KEYS = new Set(["nodes", "edges", STYLE_BLOCK_NAME]);
|
|
1355
1398
|
/** The keys of a graphology serialization the reader reads. */
|
|
1356
|
-
const GRAPHOLOGY_DOCUMENT_KEYS = new Set([
|
|
1399
|
+
const GRAPHOLOGY_DOCUMENT_KEYS = new Set([
|
|
1400
|
+
"nodes",
|
|
1401
|
+
"edges",
|
|
1402
|
+
"options",
|
|
1403
|
+
"attributes",
|
|
1404
|
+
STYLE_BLOCK_NAME,
|
|
1405
|
+
]);
|
|
1357
1406
|
/** The keys of a JGF graph object the reader reads. */
|
|
1358
1407
|
const JGF_GRAPH_KEYS = new Set([
|
|
1359
1408
|
"id",
|
|
@@ -1392,94 +1441,33 @@ function isIndexBelow(value, bound) {
|
|
|
1392
1441
|
*/
|
|
1393
1442
|
function importNodeLink(ctx, root, dialect) {
|
|
1394
1443
|
const { report, json } = ctx;
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
edgesKey = hasKey(root, "edges") || !hasKey(root, "links") ? "edges" : "links";
|
|
1398
|
-
}
|
|
1399
|
-
const nodes = arraySection(root.nodes, "nodes", report);
|
|
1400
|
-
const edges = arraySection(root[edgesKey], edgesKey, report);
|
|
1401
|
-
if (nodes === null) {
|
|
1402
|
-
report.warning("missing-value", JSON_ISSUE.MISSING_SECTION, "the document has no nodes array; nodes come from the edges", { element: "nodes" });
|
|
1403
|
-
ctx.nodesFromEdges = true;
|
|
1404
|
-
}
|
|
1405
|
-
if (edges === null) {
|
|
1406
|
-
report.warning("missing-value", JSON_ISSUE.MISSING_SECTION, `the document has no ${edgesKey} array; the graph has no edges`, { element: edgesKey });
|
|
1407
|
-
}
|
|
1444
|
+
const edgesKey = json.edgesKey ?? (hasKey(root, "edges") || !hasKey(root, "links") ? "edges" : "links");
|
|
1445
|
+
const { nodeList, edgeList } = nodeLinkSections(ctx, root, edgesKey);
|
|
1408
1446
|
const directed = flagOf(root.directed, "directed", ctx.defaultDirected(dialect), report);
|
|
1409
1447
|
const multigraph = hasKey(root, "multigraph") ? flagOf(root.multigraph, "multigraph", false, report) : null;
|
|
1410
1448
|
ctx.setHeader(directed);
|
|
1411
1449
|
ctx.writeGraphDict(root.graph, "graph");
|
|
1412
|
-
reportUnreadKeys(ctx, root, new Set(["nodes", edgesKey, "directed", "multigraph", "graph"]), "");
|
|
1413
|
-
|
|
1414
|
-
const
|
|
1450
|
+
reportUnreadKeys(ctx, root, new Set(["nodes", edgesKey, "directed", "multigraph", "graph", STYLE_BLOCK_NAME]), "");
|
|
1451
|
+
// NetworkX's node_link_data writes all three keys; its drawing defaults then apply
|
|
1452
|
+
const networkx = hasKey(root, "directed") && hasKey(root, "multigraph") && hasKey(root, "graph");
|
|
1453
|
+
ctx.styleSource = { dialect, block: blockOf(root), networkx };
|
|
1415
1454
|
ctx.sink.reserve(nodeList.length, edgeList.length);
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
let { nodeIdKey } = json;
|
|
1419
|
-
let positional = ctx.options.nodeIdFrom === "index";
|
|
1420
|
-
if (!positional && nodeIdKey === null) {
|
|
1421
|
-
const candidates = ctx.options.nodeIdFrom === "label" ? ["label", "name", "id"] : ["id", "name"];
|
|
1422
|
-
nodeIdKey = candidates.find((key) => anyHas(nodeList, key)) ?? null;
|
|
1423
|
-
if (ctx.options.nodeIdFrom === "label" && (nodeIdKey === "id" || nodeIdKey === "name")) {
|
|
1424
|
-
report.warning("unsupported", JSON_ISSUE.OPTION_IGNORED, nodeIdKey === "id"
|
|
1425
|
-
? 'nodeIdFrom "label": no node has a label or name key; ids are read from "id"'
|
|
1426
|
-
: 'nodeIdFrom "label": no node has a "label" key; ids are read from "name"', { element: "nodeIdFrom" });
|
|
1427
|
-
}
|
|
1428
|
-
if (nodeIdKey === null) {
|
|
1429
|
-
if (nodeList.length > 0) {
|
|
1430
|
-
positional = true;
|
|
1431
|
-
report.warning("missing-value", JSON_ISSUE.POSITIONAL_NODES, "no node has an id or name key; array positions are the node ids", { element: "nodes" });
|
|
1432
|
-
}
|
|
1433
|
-
else {
|
|
1434
|
-
nodeIdKey = "id";
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
if (positional) {
|
|
1439
|
-
nodeIdKey = null;
|
|
1440
|
-
}
|
|
1455
|
+
const nodeIdKey = nodeLinkIdKey(ctx, nodeList);
|
|
1456
|
+
const positional = nodeIdKey === null;
|
|
1441
1457
|
let indexLinks;
|
|
1442
1458
|
if (positional) {
|
|
1443
1459
|
indexLinks = true;
|
|
1444
1460
|
}
|
|
1445
1461
|
else if (json.indexLinks === "auto") {
|
|
1446
|
-
indexLinks =
|
|
1462
|
+
indexLinks = looksIndexLinked(nodeList, edgeList, nodeIdKey, json);
|
|
1447
1463
|
}
|
|
1448
1464
|
else {
|
|
1449
1465
|
({ indexLinks } = json);
|
|
1450
1466
|
}
|
|
1451
|
-
|
|
1452
|
-
if (indexLinks && !positional && json.indexLinks === "auto" && nodeIdKey !== null) {
|
|
1467
|
+
if (indexLinks && !positional && json.indexLinks === "auto") {
|
|
1453
1468
|
reportAmbiguousIndexLinks(ctx, nodeList, edgeList, nodeIdKey);
|
|
1454
1469
|
}
|
|
1455
|
-
|
|
1456
|
-
const element = `nodes[${i}]`;
|
|
1457
|
-
const record = nodeList[i];
|
|
1458
|
-
let pushed = null;
|
|
1459
|
-
if (!isJsonObject(record)) {
|
|
1460
|
-
ctx.badElement("node", element);
|
|
1461
|
-
}
|
|
1462
|
-
else {
|
|
1463
|
-
let id;
|
|
1464
|
-
if (nodeIdKey === null) {
|
|
1465
|
-
id = i;
|
|
1466
|
-
}
|
|
1467
|
-
else {
|
|
1468
|
-
id = ctx.coerceId(hasKey(record, nodeIdKey) ? record[nodeIdKey] : undefined, element);
|
|
1469
|
-
}
|
|
1470
|
-
if (id === null) {
|
|
1471
|
-
ctx.countSkipped("node");
|
|
1472
|
-
}
|
|
1473
|
-
else {
|
|
1474
|
-
const index = ctx.pushNode(id, element);
|
|
1475
|
-
if (index >= 0) {
|
|
1476
|
-
pushed = id;
|
|
1477
|
-
writeFlat(ctx.nodes, index, record, id, (key) => key !== nodeIdKey);
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
}
|
|
1481
|
-
positionIds?.push(pushed);
|
|
1482
|
-
}
|
|
1470
|
+
const positionIds = importNodeLinkNodes(ctx, nodeList, nodeIdKey, indexLinks);
|
|
1483
1471
|
throwIfAborted(ctx.options.signal);
|
|
1484
1472
|
const endpointKeys = importNodeLinkEdges(ctx, edgeList, edgesKey, positionIds, multigraph);
|
|
1485
1473
|
ctx.setMeta({
|
|
@@ -1491,6 +1479,103 @@ function importNodeLink(ctx, root, dialect) {
|
|
|
1491
1479
|
targetKey: endpointKeys.target ?? undefined,
|
|
1492
1480
|
}, { declaredMultigraph: multigraph, ...ctx.weightOriginPatch() });
|
|
1493
1481
|
}
|
|
1482
|
+
/**
|
|
1483
|
+
* The node and edge arrays of a node-link or d3 document; a missing one is reported (without nodes, nodes come from
|
|
1484
|
+
* the edges).
|
|
1485
|
+
* @param ctx - the context
|
|
1486
|
+
* @param root - the document
|
|
1487
|
+
* @param edgesKey - the key of the edges
|
|
1488
|
+
* @returns the arrays, empty when missing
|
|
1489
|
+
*/
|
|
1490
|
+
function nodeLinkSections(ctx, root, edgesKey) {
|
|
1491
|
+
const { report } = ctx;
|
|
1492
|
+
const nodes = arraySection(root.nodes, "nodes", report);
|
|
1493
|
+
const edges = arraySection(root[edgesKey], edgesKey, report);
|
|
1494
|
+
if (nodes === null) {
|
|
1495
|
+
report.warning("missing-value", JSON_ISSUE.MISSING_SECTION, "the document has no nodes array; nodes come from the edges", { element: "nodes" });
|
|
1496
|
+
ctx.nodesFromEdges = true;
|
|
1497
|
+
}
|
|
1498
|
+
if (edges === null) {
|
|
1499
|
+
report.warning("missing-value", JSON_ISSUE.MISSING_SECTION, `the document has no ${edgesKey} array; the graph has no edges`, { element: edgesKey });
|
|
1500
|
+
}
|
|
1501
|
+
return { nodeList: nodes ?? [], edgeList: edges ?? [] };
|
|
1502
|
+
}
|
|
1503
|
+
/**
|
|
1504
|
+
* The key node ids are read from: the caller's, else "id" when any node has it, else "name" (d3); null when the nodes
|
|
1505
|
+
* are positional (nodeIdFrom "index", or a d3 v3 file whose nodes carry no id at all).
|
|
1506
|
+
* @param ctx - the context
|
|
1507
|
+
* @param nodeList - the node records
|
|
1508
|
+
* @returns the key, or null for positional nodes
|
|
1509
|
+
*/
|
|
1510
|
+
function nodeLinkIdKey(ctx, nodeList) {
|
|
1511
|
+
const { report, json } = ctx;
|
|
1512
|
+
if (ctx.options.nodeIdFrom === "index") {
|
|
1513
|
+
return null;
|
|
1514
|
+
}
|
|
1515
|
+
if (json.nodeIdKey !== null) {
|
|
1516
|
+
return json.nodeIdKey;
|
|
1517
|
+
}
|
|
1518
|
+
const byLabel = ctx.options.nodeIdFrom === "label";
|
|
1519
|
+
const candidates = byLabel ? ["label", "name", "id"] : ["id", "name"];
|
|
1520
|
+
const found = candidates.find((key) => anyHas(nodeList, key)) ?? null;
|
|
1521
|
+
if (byLabel && (found === "id" || found === "name")) {
|
|
1522
|
+
report.warning("unsupported", JSON_ISSUE.OPTION_IGNORED, found === "id"
|
|
1523
|
+
? 'nodeIdFrom "label": no node has a label or name key; ids are read from "id"'
|
|
1524
|
+
: 'nodeIdFrom "label": no node has a "label" key; ids are read from "name"', { element: "nodeIdFrom" });
|
|
1525
|
+
}
|
|
1526
|
+
if (found !== null || nodeList.length === 0) {
|
|
1527
|
+
return found ?? "id";
|
|
1528
|
+
}
|
|
1529
|
+
report.warning("missing-value", JSON_ISSUE.POSITIONAL_NODES, "no node has an id or name key; array positions are the node ids", { element: "nodes" });
|
|
1530
|
+
return null;
|
|
1531
|
+
}
|
|
1532
|
+
/**
|
|
1533
|
+
* Read the node-link / d3 node records.
|
|
1534
|
+
* @param ctx - the context
|
|
1535
|
+
* @param nodeList - the node records
|
|
1536
|
+
* @param nodeIdKey - the key ids are read from, or null for positional nodes
|
|
1537
|
+
* @param indexLinks - whether edges name their endpoints by array position
|
|
1538
|
+
* @returns the ids by array position under index links (null where a node was not added), else null
|
|
1539
|
+
*/
|
|
1540
|
+
function importNodeLinkNodes(ctx, nodeList, nodeIdKey, indexLinks) {
|
|
1541
|
+
const positionIds = indexLinks ? [] : null;
|
|
1542
|
+
for (let i = 0; i < nodeList.length; i++) {
|
|
1543
|
+
const element = `nodes[${i}]`;
|
|
1544
|
+
const record = nodeList[i];
|
|
1545
|
+
let pushed = null;
|
|
1546
|
+
if (isJsonObject(record)) {
|
|
1547
|
+
pushed = pushNodeLinkNode(ctx, record, i, nodeIdKey);
|
|
1548
|
+
}
|
|
1549
|
+
else {
|
|
1550
|
+
ctx.badElement("node", element);
|
|
1551
|
+
}
|
|
1552
|
+
positionIds?.push(pushed);
|
|
1553
|
+
}
|
|
1554
|
+
return positionIds;
|
|
1555
|
+
}
|
|
1556
|
+
/**
|
|
1557
|
+
* Add one node-link / d3 node and its other keys as attributes.
|
|
1558
|
+
* @param ctx - the context
|
|
1559
|
+
* @param record - the node record
|
|
1560
|
+
* @param i - its array position
|
|
1561
|
+
* @param nodeIdKey - the key its id is read from, or null for positional nodes
|
|
1562
|
+
* @returns its id, or null when it was not added
|
|
1563
|
+
*/
|
|
1564
|
+
function pushNodeLinkNode(ctx, record, i, nodeIdKey) {
|
|
1565
|
+
const element = `nodes[${i}]`;
|
|
1566
|
+
const raw = nodeIdKey !== null && hasKey(record, nodeIdKey) ? record[nodeIdKey] : undefined;
|
|
1567
|
+
const id = nodeIdKey === null ? i : ctx.coerceId(raw, element);
|
|
1568
|
+
if (id === null) {
|
|
1569
|
+
ctx.countSkipped("node");
|
|
1570
|
+
return null;
|
|
1571
|
+
}
|
|
1572
|
+
const index = ctx.pushNode(id, element);
|
|
1573
|
+
if (index < 0) {
|
|
1574
|
+
return null;
|
|
1575
|
+
}
|
|
1576
|
+
writeFlat(ctx.nodes, index, record, id, (key) => key !== nodeIdKey);
|
|
1577
|
+
return id;
|
|
1578
|
+
}
|
|
1494
1579
|
/**
|
|
1495
1580
|
* Read the node-link / d3 edge records: endpoints by id or array position, the weight, the other
|
|
1496
1581
|
* keys as attributes.
|
|
@@ -1769,6 +1854,7 @@ function importVis(ctx, root) {
|
|
|
1769
1854
|
if (arrows > 0) {
|
|
1770
1855
|
report.warning("validation-error", JSON_ISSUE.INCONSISTENT, `${arrows} edge${plural(arrows)} ${agree(arrows, "carries", "carry")} vis.js arrows but the graph is read undirected; the arrows are kept as an attribute (pass defaultDirected: true to read the edges as directed)`, { element: "arrows" });
|
|
1771
1856
|
}
|
|
1857
|
+
ctx.styleSource = { dialect: "vis", block: blockOf(root), options: root.options, groups: root.groups };
|
|
1772
1858
|
ctx.setMeta({ dialect: "vis", nodeIdKey, sourceKey: sourceKey ?? undefined, targetKey: targetKey ?? undefined }, ctx.weightOriginPatch());
|
|
1773
1859
|
}
|
|
1774
1860
|
// ============================================================ NetworkX adjacency_data / tree_data
|
|
@@ -2082,36 +2168,29 @@ function importGraphology(ctx, root) {
|
|
|
2082
2168
|
});
|
|
2083
2169
|
}
|
|
2084
2170
|
const type = graphologyType(ctx, options);
|
|
2085
|
-
ctx.setHeader(
|
|
2171
|
+
ctx.setHeader(type === "mixed" ? mostlyDirected(ctx, edges) : type === "directed");
|
|
2086
2172
|
const multi = hasKey(options, "multi") ? flagOf(options.multi, "options.multi", false, report) : null;
|
|
2087
2173
|
const allowSelfLoops = hasKey(options, "allowSelfLoops")
|
|
2088
2174
|
? flagOf(options.allowSelfLoops, "options.allowSelfLoops", true, report)
|
|
2089
2175
|
: undefined;
|
|
2090
2176
|
ctx.writeGraphDict(root.attributes, "attributes");
|
|
2177
|
+
// Gephi's JSON export (for sigma.js) names nodes and edges by `id` and puts sigma's display keys (`label`, `x`,
|
|
2178
|
+
// `y`, `color`, `size`) beside `attributes`; they are read as attributes, not as unknown element keys
|
|
2179
|
+
const firstNode = nodes.find((n) => isJsonObject(n));
|
|
2180
|
+
const gephi = isJsonObject(firstNode) && !hasKey(firstNode, "key") && hasKey(firstNode, "id");
|
|
2181
|
+
ctx.styleSource = { dialect: "graphology", block: blockOf(root), gephi };
|
|
2091
2182
|
ctx.reportNodeIdFrom("graphology", "the node key");
|
|
2092
2183
|
ctx.sink.reserve(nodes.length, edges.length);
|
|
2093
|
-
|
|
2094
|
-
pushGraphologyNode(ctx, nodes[i], `nodes[${i}]`);
|
|
2095
|
-
}
|
|
2184
|
+
importGraphologyNodes(ctx, nodes, gephi);
|
|
2096
2185
|
throwIfAborted(ctx.options.signal);
|
|
2097
|
-
const
|
|
2098
|
-
|
|
2099
|
-
type,
|
|
2100
|
-
allowSelfLoops,
|
|
2101
|
-
// what the edges do against the declared options: graphology itself refuses such a document
|
|
2102
|
-
violations: { selfLoops: 0, parallels: 0, flags: 0 },
|
|
2103
|
-
pairs: multi === false ? new Set() : null,
|
|
2104
|
-
};
|
|
2105
|
-
for (let i = 0; i < edges.length; i++) {
|
|
2106
|
-
readGraphologyEdge(ctx, reading, edges[i], `edges[${i}]`);
|
|
2107
|
-
}
|
|
2108
|
-
reportGraphologyViolations(ctx, reading.violations, type);
|
|
2186
|
+
const violations = importGraphologyEdges(ctx, edges, { type, gephi, multi, allowSelfLoops });
|
|
2187
|
+
reportGraphologyViolations(ctx, violations, type);
|
|
2109
2188
|
ctx.setMeta({ dialect: "graphology", allowSelfLoops }, { declaredMultigraph: multi, ...ctx.weightOriginPatch() });
|
|
2110
2189
|
}
|
|
2111
2190
|
/**
|
|
2112
|
-
* A graphology document's `options.type
|
|
2191
|
+
* A graphology document's `options.type`: "mixed" when absent or not one of the three (reported).
|
|
2113
2192
|
* @param ctx - the context
|
|
2114
|
-
* @param options - the options
|
|
2193
|
+
* @param options - the document's options
|
|
2115
2194
|
* @returns the type
|
|
2116
2195
|
*/
|
|
2117
2196
|
function graphologyType(ctx, options) {
|
|
@@ -2124,114 +2203,133 @@ function graphologyType(ctx, options) {
|
|
|
2124
2203
|
return "mixed";
|
|
2125
2204
|
}
|
|
2126
2205
|
/**
|
|
2127
|
-
* The header direction of a graphology
|
|
2128
|
-
* edge object says undirected (the dialect default when there is none).
|
|
2206
|
+
* The header direction of a mixed graphology graph: directed unless every edge is flagged undirected.
|
|
2129
2207
|
* @param ctx - the context
|
|
2130
|
-
* @param type - options.type
|
|
2131
2208
|
* @param edges - the edge records
|
|
2132
|
-
* @returns
|
|
2209
|
+
* @returns true for directed
|
|
2133
2210
|
*/
|
|
2134
|
-
function
|
|
2135
|
-
if (type !== "mixed") {
|
|
2136
|
-
return type === "directed";
|
|
2137
|
-
}
|
|
2211
|
+
function mostlyDirected(ctx, edges) {
|
|
2138
2212
|
const objects = edges.filter((edge) => isJsonObject(edge));
|
|
2139
2213
|
const undirectedEdges = objects.filter((edge) => edge.undirected === true).length;
|
|
2140
2214
|
return objects.length === 0 ? ctx.defaultDirected("graphology") : undirectedEdges < objects.length;
|
|
2141
2215
|
}
|
|
2142
2216
|
/**
|
|
2143
|
-
*
|
|
2217
|
+
* Read the graphology node records.
|
|
2144
2218
|
* @param ctx - the context
|
|
2145
|
-
* @param
|
|
2146
|
-
* @param
|
|
2219
|
+
* @param nodes - the node records
|
|
2220
|
+
* @param gephi - whether Gephi wrote them (ids under `id`, display keys beside the attributes)
|
|
2147
2221
|
*/
|
|
2148
|
-
function
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2222
|
+
function importGraphologyNodes(ctx, nodes, gephi) {
|
|
2223
|
+
const nodeKey = gephi ? "id" : "key";
|
|
2224
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
2225
|
+
const element = `nodes[${i}]`;
|
|
2226
|
+
const record = nodes[i];
|
|
2227
|
+
if (!isJsonObject(record)) {
|
|
2228
|
+
ctx.badElement("node", element);
|
|
2229
|
+
continue;
|
|
2230
|
+
}
|
|
2231
|
+
const id = ctx.coerceId(hasKey(record, nodeKey) ? record[nodeKey] : undefined, element);
|
|
2232
|
+
if (id === null) {
|
|
2233
|
+
ctx.countSkipped("node");
|
|
2234
|
+
continue;
|
|
2235
|
+
}
|
|
2236
|
+
pushNestedNode(ctx, id, record, "attributes", gephi ? GEPHI_NODE_KEYS : GRAPHOLOGY_NODE_KEYS, element, gephi);
|
|
2157
2237
|
}
|
|
2158
|
-
pushNestedNode(ctx, id, record, "attributes", GRAPHOLOGY_NODE_KEYS, element);
|
|
2159
2238
|
}
|
|
2160
2239
|
/**
|
|
2161
|
-
* Read
|
|
2240
|
+
* Read the graphology edge records.
|
|
2162
2241
|
* @param ctx - the context
|
|
2163
|
-
* @param
|
|
2164
|
-
* @param
|
|
2165
|
-
* @
|
|
2166
|
-
*/
|
|
2167
|
-
function
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
const u = ctx.coerceId(record.source, `${element}.source`);
|
|
2178
|
-
const v = ctx.coerceId(record.target, `${element}.target`);
|
|
2179
|
-
if (u === null || v === null) {
|
|
2180
|
-
ctx.countSkipped("edge");
|
|
2181
|
-
return;
|
|
2242
|
+
* @param edges - the edge records
|
|
2243
|
+
* @param declared - what the document declares
|
|
2244
|
+
* @returns the edges that contradict the declared options: graphology itself refuses such a document
|
|
2245
|
+
*/
|
|
2246
|
+
function importGraphologyEdges(ctx, edges, declared) {
|
|
2247
|
+
const { gephi } = declared;
|
|
2248
|
+
const ids = ctx.declareEdgeIds(edges, (edge) => (gephi && !hasKey(edge, "key") ? edge.id : edge.key), "key", true);
|
|
2249
|
+
const violations = { selfLoops: 0, parallels: 0, flags: 0 };
|
|
2250
|
+
const pairs = declared.multi === false ? new Set() : null;
|
|
2251
|
+
for (let i = 0; i < edges.length; i++) {
|
|
2252
|
+
const element = `edges[${i}]`;
|
|
2253
|
+
const record = graphologyEdgeRecord(ctx, edges[i], element);
|
|
2254
|
+
if (record === null) {
|
|
2255
|
+
continue;
|
|
2182
2256
|
}
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
if (reading.allowSelfLoops === false && u === v) {
|
|
2190
|
-
reading.violations.selfLoops++;
|
|
2257
|
+
try {
|
|
2258
|
+
const pushed = pushGraphologyEdge(ctx, record, element, ids, declared, violations);
|
|
2259
|
+
if (pushed !== null && pairs !== null) {
|
|
2260
|
+
violations.parallels += pairs.has(pushed) ? 1 : 0;
|
|
2261
|
+
pairs.add(pushed);
|
|
2262
|
+
}
|
|
2191
2263
|
}
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
reading.violations.parallels += reading.pairs.has(pair) ? 1 : 0;
|
|
2195
|
-
reading.pairs.add(pair);
|
|
2264
|
+
catch (err) {
|
|
2265
|
+
ctx.skip(err, "edge", element);
|
|
2196
2266
|
}
|
|
2197
2267
|
}
|
|
2198
|
-
|
|
2199
|
-
ctx.skip(err, "edge", element);
|
|
2200
|
-
}
|
|
2268
|
+
return violations;
|
|
2201
2269
|
}
|
|
2202
2270
|
/**
|
|
2203
|
-
*
|
|
2204
|
-
* (a contrary flag is counted as a violation).
|
|
2271
|
+
* One graphology edge record, when it is an object with both endpoints.
|
|
2205
2272
|
* @param ctx - the context
|
|
2206
|
-
* @param reading - the read's state
|
|
2207
2273
|
* @param record - the edge record
|
|
2208
2274
|
* @param element - the element name
|
|
2209
|
-
* @returns the
|
|
2275
|
+
* @returns the record, or null when it was reported and is skipped
|
|
2210
2276
|
*/
|
|
2211
|
-
function
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
return
|
|
2277
|
+
function graphologyEdgeRecord(ctx, record, element) {
|
|
2278
|
+
if (!isJsonObject(record)) {
|
|
2279
|
+
ctx.badElement("edge", element);
|
|
2280
|
+
return null;
|
|
2215
2281
|
}
|
|
2216
|
-
if (
|
|
2217
|
-
|
|
2282
|
+
if (!present(record, "source") || !present(record, "target")) {
|
|
2283
|
+
ctx.missingEndpoint(element, present(record, "source") ? "target" : "source");
|
|
2284
|
+
return null;
|
|
2218
2285
|
}
|
|
2219
|
-
return
|
|
2286
|
+
return record;
|
|
2220
2287
|
}
|
|
2221
2288
|
/**
|
|
2222
|
-
*
|
|
2223
|
-
* no attributes.
|
|
2289
|
+
* Add one graphology edge with its id and attributes.
|
|
2224
2290
|
* @param ctx - the context
|
|
2225
2291
|
* @param record - the edge record
|
|
2226
2292
|
* @param element - the element name
|
|
2227
|
-
* @
|
|
2293
|
+
* @param ids - the edge id column
|
|
2294
|
+
* @param declared - what the document declares
|
|
2295
|
+
* @param violations - counts the edges that contradict the declared options
|
|
2296
|
+
* @returns the edge's kind and endpoint pair, or null when it was skipped
|
|
2228
2297
|
*/
|
|
2229
|
-
function
|
|
2230
|
-
const {
|
|
2231
|
-
|
|
2232
|
-
|
|
2298
|
+
function pushGraphologyEdge(ctx, record, element, ids, declared, violations) {
|
|
2299
|
+
const { report } = ctx;
|
|
2300
|
+
const { type, gephi } = declared;
|
|
2301
|
+
const u = ctx.coerceId(record.source, `${element}.source`);
|
|
2302
|
+
const v = ctx.coerceId(record.target, `${element}.target`);
|
|
2303
|
+
if (u === null || v === null) {
|
|
2304
|
+
ctx.countSkipped("edge");
|
|
2305
|
+
return null;
|
|
2306
|
+
}
|
|
2307
|
+
let kind;
|
|
2308
|
+
if (type === "mixed") {
|
|
2309
|
+
kind = flagOf(record.undirected, `${element}.undirected`, false, report) ? "undirected" : "directed";
|
|
2233
2310
|
}
|
|
2234
|
-
|
|
2311
|
+
else {
|
|
2312
|
+
kind = type;
|
|
2313
|
+
if (typeof record.undirected === "boolean" && record.undirected !== (type === "undirected")) {
|
|
2314
|
+
violations.flags++;
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
const { attributes: rawAttributes } = record;
|
|
2318
|
+
if (rawAttributes !== undefined && rawAttributes !== null && !isJsonObject(rawAttributes)) {
|
|
2319
|
+
report.error("validation-error", JSON_ISSUE.BAD_VALUE, `${element}: attributes must be an object, found ${describe(rawAttributes)}`, { element });
|
|
2320
|
+
}
|
|
2321
|
+
const attributes = isJsonObject(rawAttributes) ? rawAttributes : {};
|
|
2322
|
+
const idValue = ctx.edgeIdValue(ids, record.key);
|
|
2323
|
+
const edge = ctx.pushEdge(u, v, kind, ctx.weightOf(attributes), element);
|
|
2324
|
+
ctx.setEdgeId(ids, edge, idValue);
|
|
2325
|
+
ctx.writeNested(ctx.edges, edge, record, attributes, gephi ? GEPHI_EDGE_KEYS : GRAPHOLOGY_EDGE_KEYS, element, {
|
|
2326
|
+
weightFrom: ctx.options.weightFrom,
|
|
2327
|
+
plain: gephi,
|
|
2328
|
+
});
|
|
2329
|
+
if (declared.allowSelfLoops === false && u === v) {
|
|
2330
|
+
violations.selfLoops++;
|
|
2331
|
+
}
|
|
2332
|
+
return `${kind} ${pairKey(u, v, kind === "directed")}`;
|
|
2235
2333
|
}
|
|
2236
2334
|
/**
|
|
2237
2335
|
* Report the edges that contradict a graphology document's declared options (W_JSON_INCONSISTENT,
|
|
@@ -2269,9 +2367,10 @@ function reportGraphologyViolations(ctx, violations, type) {
|
|
|
2269
2367
|
* @param dictKey - the key of the nested dict
|
|
2270
2368
|
* @param structural - the element keys that are not attributes
|
|
2271
2369
|
* @param element - the element name
|
|
2370
|
+
* @param plain - write the element-level keys under their own names
|
|
2272
2371
|
* @returns the node index, or -1 when skipped
|
|
2273
2372
|
*/
|
|
2274
|
-
function pushNestedNode(ctx, id, record, dictKey, structural, element) {
|
|
2373
|
+
function pushNestedNode(ctx, id, record, dictKey, structural, element, plain = false) {
|
|
2275
2374
|
const index = ctx.pushNode(id, element);
|
|
2276
2375
|
if (index < 0) {
|
|
2277
2376
|
return index;
|
|
@@ -2281,7 +2380,7 @@ function pushNestedNode(ctx, id, record, dictKey, structural, element) {
|
|
|
2281
2380
|
if (dict !== undefined && dict !== null && !isJsonObject(dict)) {
|
|
2282
2381
|
ctx.report.error("validation-error", JSON_ISSUE.BAD_VALUE, `${element}: ${dictKey} must be an object, found ${describe(dict)}`, { element });
|
|
2283
2382
|
}
|
|
2284
|
-
ctx.writeNested(ctx.nodes, index, record, isJsonObject(dict) ? dict : {}, structural,
|
|
2383
|
+
ctx.writeNested(ctx.nodes, index, record, isJsonObject(dict) ? dict : {}, structural, element, { plain });
|
|
2285
2384
|
}
|
|
2286
2385
|
catch (err) {
|
|
2287
2386
|
ctx.report.recordError(err, { element: String(id) });
|
|
@@ -2319,7 +2418,7 @@ function importJgf(ctx, root) {
|
|
|
2319
2418
|
ctx.sink.reserve(nodeRecords.length, edges.length);
|
|
2320
2419
|
const labelColumn = ctx.nodes.declareIf({ name: "label", dtype: "string", role: "label", nullable: true }, anyHas(nodeRecords, "label"));
|
|
2321
2420
|
if (isJsonObject(nodesRaw)) {
|
|
2322
|
-
for (const key of
|
|
2421
|
+
for (const key of jgfNodeKeys(ctx, root, graph, nodesRaw)) {
|
|
2323
2422
|
pushJgfKeyedNode(ctx, key, nodesRaw[key], labelColumn);
|
|
2324
2423
|
}
|
|
2325
2424
|
}
|
|
@@ -2425,7 +2524,7 @@ function jgfEdgeWriter(ctx, edges, hyperedges) {
|
|
|
2425
2524
|
element,
|
|
2426
2525
|
});
|
|
2427
2526
|
}
|
|
2428
|
-
ctx.writeNested(ctx.edges, edge, record, dict, structural, ctx.options.weightFrom
|
|
2527
|
+
ctx.writeNested(ctx.edges, edge, record, dict, structural, element, { weightFrom: ctx.options.weightFrom });
|
|
2429
2528
|
};
|
|
2430
2529
|
}
|
|
2431
2530
|
/**
|
|
@@ -2459,6 +2558,25 @@ function readJgfEdge(ctx, record, element, directed, writeJgfEdge) {
|
|
|
2459
2558
|
ctx.skip(err, "edge", element);
|
|
2460
2559
|
}
|
|
2461
2560
|
}
|
|
2561
|
+
/**
|
|
2562
|
+
* The keys of a JGF nodes object in the file's order, which is the nodes' order: JSON.parse puts integer-like keys
|
|
2563
|
+
* first, so then they are read from the text.
|
|
2564
|
+
* @param ctx - the context, holding the text
|
|
2565
|
+
* @param root - the document
|
|
2566
|
+
* @param graph - the graph object read
|
|
2567
|
+
* @param nodes - its nodes object
|
|
2568
|
+
* @returns the keys
|
|
2569
|
+
*/
|
|
2570
|
+
function jgfNodeKeys(ctx, root, graph, nodes) {
|
|
2571
|
+
const keys = Object.keys(nodes);
|
|
2572
|
+
if (!keys.some((k) => ARRAY_INDEX.test(k))) {
|
|
2573
|
+
return keys;
|
|
2574
|
+
}
|
|
2575
|
+
const path = isJsonObject(root.graph)
|
|
2576
|
+
? ["graph", "nodes"]
|
|
2577
|
+
: ["graphs", root.graphs.indexOf(graph), "nodes"];
|
|
2578
|
+
return keysInTextOrder(ctx.text, path) ?? keys;
|
|
2579
|
+
}
|
|
2462
2580
|
/**
|
|
2463
2581
|
* The graph object of a JGF document: `graph`, or the graph of `graphs` that graphIndex /
|
|
2464
2582
|
* graphName choose (chooseGraph()).
|
|
@@ -2612,7 +2730,7 @@ function pushJgfNode(ctx, id, record, labelColumn, element) {
|
|
|
2612
2730
|
element,
|
|
2613
2731
|
});
|
|
2614
2732
|
}
|
|
2615
|
-
ctx.writeNested(ctx.nodes, index, record, isJsonObject(metadata) ? metadata : {}, JGF_NODE_KEYS,
|
|
2733
|
+
ctx.writeNested(ctx.nodes, index, record, isJsonObject(metadata) ? metadata : {}, JGF_NODE_KEYS, element);
|
|
2616
2734
|
}
|
|
2617
2735
|
catch (err) {
|
|
2618
2736
|
ctx.report.recordError(err, { element: String(id) });
|
|
@@ -2767,42 +2885,44 @@ function distinctMembers(ctx, members, element) {
|
|
|
2767
2885
|
function importCytoscape(ctx, root) {
|
|
2768
2886
|
const { elements, extra } = cytoscapeRoot(ctx, root);
|
|
2769
2887
|
const { nodes, edges } = cytoscapeSections(ctx, elements);
|
|
2888
|
+
const generatedIds = cytoscapeGeneratedIds(nodes);
|
|
2889
|
+
ctx.styleSource = {
|
|
2890
|
+
dialect: "cytoscape",
|
|
2891
|
+
block: blockOf(root),
|
|
2892
|
+
elements: elements ?? [],
|
|
2893
|
+
style: isJsonObject(root) ? root.style : undefined,
|
|
2894
|
+
generatedBy: isJsonObject(root) && typeof root.generated_by === "string" ? root.generated_by : null,
|
|
2895
|
+
generatedIds,
|
|
2896
|
+
};
|
|
2770
2897
|
ctx.setHeader(ctx.defaultDirected("cytoscape"));
|
|
2771
2898
|
ctx.reportNodeIdFrom("cytoscape", "data.id");
|
|
2772
2899
|
ctx.sink.reserve(nodes.length, edges.length);
|
|
2773
|
-
const
|
|
2774
|
-
const reading = {
|
|
2775
|
-
positionColumn: ctx.nodes.declareIf({
|
|
2776
|
-
name: POSITION_COLUMN,
|
|
2777
|
-
dtype: "f64",
|
|
2778
|
-
components: 3,
|
|
2779
|
-
role: "position",
|
|
2780
|
-
mutable: true,
|
|
2781
|
-
nullable: true,
|
|
2782
|
-
// 3D layouts written by Cytoscape-compatible tools carry a z
|
|
2783
|
-
extra: { sourceDims: nodes.some(hasPositionZ) ? 3 : 2, units: "file" },
|
|
2784
|
-
origin: { format: "json", namespace: "cytoscape" },
|
|
2785
|
-
}, anyHas(nodes, "position")),
|
|
2786
|
-
classesColumn: ctx.nodes.declareIf({ name: CLASSES_COLUMN, dtype: "list", itemDtype: "string", role: "classes", nullable: true }, anyHas(nodes, "classes")),
|
|
2787
|
-
parents: [],
|
|
2788
|
-
point: [0, 0, 0],
|
|
2789
|
-
};
|
|
2790
|
-
const parentColumn = ctx.nodes.declareIf({ name: PARENT_COLUMN, dtype: "u32", role: "parent", refersTo: "node", nullable: true }, dataHas(nodes, "parent"));
|
|
2900
|
+
const columns = cytoscapeNodeColumns(ctx, nodes);
|
|
2791
2901
|
const edgeClassesColumn = ctx.edges.declareIf({ name: CLASSES_COLUMN, dtype: "list", itemDtype: "string", role: "classes", nullable: true }, anyHas(edges, "classes"));
|
|
2902
|
+
const parents = [];
|
|
2792
2903
|
for (let i = 0; i < nodes.length; i++) {
|
|
2793
|
-
|
|
2904
|
+
const element = `nodes[${i}]`;
|
|
2905
|
+
const record = nodes[i];
|
|
2906
|
+
if (isJsonObject(record) && isJsonObject(record.data)) {
|
|
2907
|
+
// Cytoscape.js gives a node without data.id an id of its own
|
|
2908
|
+
const raw = record.data.id === undefined ? generatedIds.get(record) : record.data.id;
|
|
2909
|
+
importCytoscapeNode(ctx, record, record.data, raw, element, columns, parents);
|
|
2910
|
+
}
|
|
2911
|
+
else {
|
|
2912
|
+
ctx.badElement("node", element, "an element with a data object");
|
|
2913
|
+
}
|
|
2794
2914
|
}
|
|
2795
|
-
resolveCytoscapeParents(ctx,
|
|
2915
|
+
resolveCytoscapeParents(ctx, parents, columns.parent);
|
|
2796
2916
|
throwIfAborted(ctx.options.signal);
|
|
2797
2917
|
importCytoscapeEdges(ctx, edges, edgeClassesColumn);
|
|
2798
2918
|
ctx.setMeta({ dialect: "cytoscape", cytoscape: extra }, ctx.weightOriginPatch());
|
|
2799
2919
|
}
|
|
2800
2920
|
/**
|
|
2801
|
-
*
|
|
2802
|
-
*
|
|
2921
|
+
* A Cytoscape document's elements, and its other top-level keys (kept in meta); its `data` is written as graph
|
|
2922
|
+
* attributes.
|
|
2803
2923
|
* @param ctx - the context
|
|
2804
|
-
* @param root - the document
|
|
2805
|
-
* @returns the elements and the other
|
|
2924
|
+
* @param root - the document: an object, or an array of elements
|
|
2925
|
+
* @returns the elements and the other keys (undefined when there are none)
|
|
2806
2926
|
*/
|
|
2807
2927
|
function cytoscapeRoot(ctx, root) {
|
|
2808
2928
|
if (Array.isArray(root)) {
|
|
@@ -2811,31 +2931,53 @@ function cytoscapeRoot(ctx, root) {
|
|
|
2811
2931
|
if (!isJsonObject(root)) {
|
|
2812
2932
|
ctx.report.fail(JSON_ISSUE.SHAPE, `a Cytoscape document must be an object or an array, found ${describe(root)}`);
|
|
2813
2933
|
}
|
|
2814
|
-
|
|
2934
|
+
const object = root;
|
|
2935
|
+
ctx.writeGraphDict(object.data, "data");
|
|
2815
2936
|
const rest = {};
|
|
2816
|
-
for (const key of Object.keys(
|
|
2817
|
-
if (key !== "elements" && key !== "data") {
|
|
2818
|
-
rest[key] =
|
|
2937
|
+
for (const key of Object.keys(object)) {
|
|
2938
|
+
if (key !== "elements" && key !== "data" && key !== STYLE_BLOCK_NAME) {
|
|
2939
|
+
rest[key] = object[key];
|
|
2819
2940
|
}
|
|
2820
2941
|
}
|
|
2821
|
-
return Object.keys(rest).length > 0 ? { elements:
|
|
2942
|
+
return Object.keys(rest).length > 0 ? { elements: object.elements, extra: rest } : { elements: object.elements };
|
|
2822
2943
|
}
|
|
2823
2944
|
/**
|
|
2824
|
-
*
|
|
2825
|
-
*
|
|
2945
|
+
* Declare the position, classes and parent columns the node records use.
|
|
2946
|
+
* @param ctx - the context
|
|
2947
|
+
* @param nodes - the node records
|
|
2948
|
+
* @returns the columns
|
|
2949
|
+
*/
|
|
2950
|
+
function cytoscapeNodeColumns(ctx, nodes) {
|
|
2951
|
+
const dataHas = (items, key) => items.some((item) => isJsonObject(item) && isJsonObject(item.data) && item.data[key] !== undefined);
|
|
2952
|
+
return {
|
|
2953
|
+
position: ctx.nodes.declareIf({
|
|
2954
|
+
name: POSITION_COLUMN,
|
|
2955
|
+
dtype: "f64",
|
|
2956
|
+
components: 3,
|
|
2957
|
+
role: "position",
|
|
2958
|
+
mutable: true,
|
|
2959
|
+
nullable: true,
|
|
2960
|
+
// 3D layouts written by Cytoscape-compatible tools carry a z
|
|
2961
|
+
extra: { sourceDims: nodes.some(hasPositionZ) ? 3 : 2, units: "file" },
|
|
2962
|
+
origin: { format: "json", namespace: "cytoscape" },
|
|
2963
|
+
}, anyHas(nodes, "position")),
|
|
2964
|
+
classes: ctx.nodes.declareIf({ name: CLASSES_COLUMN, dtype: "list", itemDtype: "string", role: "classes", nullable: true }, anyHas(nodes, "classes")),
|
|
2965
|
+
parent: ctx.nodes.declareIf({ name: PARENT_COLUMN, dtype: "u32", role: "parent", refersTo: "node", nullable: true }, dataHas(nodes, "parent")),
|
|
2966
|
+
};
|
|
2967
|
+
}
|
|
2968
|
+
/**
|
|
2969
|
+
* Add one Cytoscape node: its data as attributes (its parent kept for later), its position, classes and element keys.
|
|
2826
2970
|
* @param ctx - the context
|
|
2827
|
-
* @param reading - the read's state
|
|
2828
2971
|
* @param record - the element
|
|
2972
|
+
* @param data - its data object
|
|
2973
|
+
* @param raw - its raw id
|
|
2829
2974
|
* @param element - the element name
|
|
2975
|
+
* @param columns - the node columns
|
|
2976
|
+
* @param parents - receives its parent link
|
|
2830
2977
|
*/
|
|
2831
|
-
function
|
|
2978
|
+
function importCytoscapeNode(ctx, record, data, raw, element, columns, parents) {
|
|
2832
2979
|
const { report } = ctx;
|
|
2833
|
-
|
|
2834
|
-
ctx.badElement("node", element, "an element with a data object");
|
|
2835
|
-
return;
|
|
2836
|
-
}
|
|
2837
|
-
const { data } = record;
|
|
2838
|
-
const id = ctx.coerceId(hasKey(data, "id") ? data.id : undefined, element);
|
|
2980
|
+
const id = ctx.coerceId(raw, element);
|
|
2839
2981
|
if (id === null) {
|
|
2840
2982
|
ctx.countSkipped("node");
|
|
2841
2983
|
return;
|
|
@@ -2848,9 +2990,18 @@ function readCytoscapeNode(ctx, reading, record, element) {
|
|
|
2848
2990
|
report.warning("validation-error", JSON_ISSUE.INCONSISTENT, `${element} has data.source and data.target, the shape of an edge, but its section or group says node; read as a node`, { element });
|
|
2849
2991
|
}
|
|
2850
2992
|
try {
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2993
|
+
for (const key of Object.keys(data).filter((k) => k !== "id")) {
|
|
2994
|
+
if (key !== "parent") {
|
|
2995
|
+
ctx.nodes.write(index, key, data[key], SUFFIX.data, element);
|
|
2996
|
+
continue;
|
|
2997
|
+
}
|
|
2998
|
+
const parent = data.parent === null ? null : ctx.coerceId(data.parent, `${element}.data.parent`);
|
|
2999
|
+
if (parent !== null) {
|
|
3000
|
+
parents.push({ index, parent, element });
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
writeCytoscapePosition(ctx, columns.position, index, record.position, element);
|
|
3004
|
+
writeClasses(ctx, ctx.nodes, columns.classes, index, record.classes, element);
|
|
2854
3005
|
writeElementKeys(ctx.nodes, index, record, element);
|
|
2855
3006
|
}
|
|
2856
3007
|
catch (err) {
|
|
@@ -2858,53 +3009,21 @@ function readCytoscapeNode(ctx, reading, record, element) {
|
|
|
2858
3009
|
}
|
|
2859
3010
|
}
|
|
2860
3011
|
/**
|
|
2861
|
-
* Write a Cytoscape node's
|
|
2862
|
-
*
|
|
2863
|
-
* @param reading - the read's state
|
|
2864
|
-
* @param index - the node index
|
|
2865
|
-
* @param data - the element's data object
|
|
2866
|
-
* @param element - the element name
|
|
2867
|
-
*/
|
|
2868
|
-
function writeCytoscapeData(ctx, reading, index, data, element) {
|
|
2869
|
-
for (const key of Object.keys(data)) {
|
|
2870
|
-
if (key === "id") {
|
|
2871
|
-
continue;
|
|
2872
|
-
}
|
|
2873
|
-
if (key !== "parent") {
|
|
2874
|
-
ctx.nodes.write(index, key, data[key], SUFFIX.data, element);
|
|
2875
|
-
continue;
|
|
2876
|
-
}
|
|
2877
|
-
const raw = data.parent;
|
|
2878
|
-
if (raw === undefined || raw === null) {
|
|
2879
|
-
continue;
|
|
2880
|
-
}
|
|
2881
|
-
const parent = ctx.coerceId(raw, `${element}.data.parent`);
|
|
2882
|
-
if (parent !== null) {
|
|
2883
|
-
reading.parents.push({ index, parent, element });
|
|
2884
|
-
}
|
|
2885
|
-
}
|
|
2886
|
-
}
|
|
2887
|
-
/**
|
|
2888
|
-
* Write a Cytoscape node's `position` ({ x, y, z? }, y flipped to grow upward); any other value is
|
|
2889
|
-
* reported.
|
|
3012
|
+
* Write a Cytoscape node's position, y flipped (Cytoscape's y grows downward; positions are stored y-up and the
|
|
3013
|
+
* exporter flips back).
|
|
2890
3014
|
* @param ctx - the context
|
|
2891
|
-
* @param
|
|
2892
|
-
* @param index - the node
|
|
3015
|
+
* @param column - the position column
|
|
3016
|
+
* @param index - the node
|
|
2893
3017
|
* @param position - the element's position
|
|
2894
3018
|
* @param element - the element name
|
|
2895
3019
|
*/
|
|
2896
|
-
function writeCytoscapePosition(ctx,
|
|
3020
|
+
function writeCytoscapePosition(ctx, column, index, position, element) {
|
|
2897
3021
|
if (position === undefined || position === null) {
|
|
2898
3022
|
return;
|
|
2899
3023
|
}
|
|
2900
3024
|
const z = isJsonObject(position) ? (position.z ?? 0) : 0;
|
|
2901
3025
|
if (isJsonObject(position) && isCoordinate(position.x) && isCoordinate(position.y) && isCoordinate(z)) {
|
|
2902
|
-
|
|
2903
|
-
point[0] = position.x;
|
|
2904
|
-
// Cytoscape's y grows downward; positions are stored y-up (the exporter flips back)
|
|
2905
|
-
point[1] = flipY(position.y);
|
|
2906
|
-
point[2] = z;
|
|
2907
|
-
ctx.nodes.set(reading.positionColumn, index, point);
|
|
3026
|
+
ctx.nodes.set(column, index, [position.x, flipY(position.y), z]);
|
|
2908
3027
|
}
|
|
2909
3028
|
else {
|
|
2910
3029
|
ctx.report.error("validation-error", JSON_ISSUE.BAD_VALUE, `${element}: position must be an object with numeric x and y (and z) that are finite numbers`, { element });
|
|
@@ -2923,7 +3042,11 @@ function resolveCytoscapeParents(ctx, parents, parentColumn) {
|
|
|
2923
3042
|
// the last link per child (a duplicate node's later parent wins), child -> its link
|
|
2924
3043
|
const linkOf = new Map();
|
|
2925
3044
|
for (let order = 0; order < parents.length; order++) {
|
|
2926
|
-
const { index,
|
|
3045
|
+
const { index, element } = parents[order];
|
|
3046
|
+
let { parent } = parents[order];
|
|
3047
|
+
if (ctx.sink.indexOf(parent) === INVALID_INDEX) {
|
|
3048
|
+
parent = ctx.textualId(parent, element) ?? parent;
|
|
3049
|
+
}
|
|
2927
3050
|
const parentIndex = ctx.sink.indexOf(parent);
|
|
2928
3051
|
if (parentIndex === INVALID_INDEX) {
|
|
2929
3052
|
report.error("missing-value", JSON_ISSUE.UNKNOWN_PARENT, `${element}: parent ${JSON.stringify(parent)} is not a node`, { element });
|
|
@@ -3014,8 +3137,8 @@ function importCytoscapeEdges(ctx, edges, edgeClassesColumn) {
|
|
|
3014
3137
|
function importCytoscapeEdge(ctx, shared, record, data, element) {
|
|
3015
3138
|
const { ids, kind, edgeClassesColumn } = shared;
|
|
3016
3139
|
try {
|
|
3017
|
-
const u = ctx.
|
|
3018
|
-
const v = ctx.
|
|
3140
|
+
const u = ctx.textualId(data.source, `${element}.data.source`);
|
|
3141
|
+
const v = ctx.textualId(data.target, `${element}.data.target`);
|
|
3019
3142
|
if (u === null || v === null) {
|
|
3020
3143
|
ctx.countSkipped("edge");
|
|
3021
3144
|
return;
|
|
@@ -3071,6 +3194,45 @@ function cytoscapeSections(ctx, elements) {
|
|
|
3071
3194
|
}
|
|
3072
3195
|
return report.fail(JSON_ISSUE.SHAPE, `elements must be an object or an array, found ${describe(elements)}`);
|
|
3073
3196
|
}
|
|
3197
|
+
/**
|
|
3198
|
+
* The ids Cytoscape.js would give the nodes without a `data.id`: `n<k>` by their place among the nodes, made unique
|
|
3199
|
+
* against every id the file states.
|
|
3200
|
+
* @param nodes - the node elements
|
|
3201
|
+
* @returns the generated id of each node element without one
|
|
3202
|
+
*/
|
|
3203
|
+
function cytoscapeGeneratedIds(nodes) {
|
|
3204
|
+
const out = new Map();
|
|
3205
|
+
const missing = nodes.filter((n) => isJsonObject(n) && isJsonObject(n.data) && n.data.id === undefined);
|
|
3206
|
+
if (missing.length === 0) {
|
|
3207
|
+
return out;
|
|
3208
|
+
}
|
|
3209
|
+
const taken = new Set();
|
|
3210
|
+
for (const n of nodes) {
|
|
3211
|
+
const id = isJsonObject(n) && isJsonObject(n.data) ? n.data.id : undefined;
|
|
3212
|
+
if (typeof id === "string" || typeof id === "number") {
|
|
3213
|
+
taken.add(String(id));
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
3216
|
+
for (let k = 0; k < missing.length; k++) {
|
|
3217
|
+
let id = `n${String(k)}`;
|
|
3218
|
+
let j = 2;
|
|
3219
|
+
while (taken.has(id)) {
|
|
3220
|
+
id = `n${String(k)}_${String(j)}`;
|
|
3221
|
+
j++;
|
|
3222
|
+
}
|
|
3223
|
+
taken.add(id);
|
|
3224
|
+
out.set(missing[k], id);
|
|
3225
|
+
}
|
|
3226
|
+
return out;
|
|
3227
|
+
}
|
|
3228
|
+
/**
|
|
3229
|
+
* A `graphty.styles` block a document holds as a top-level key, or null.
|
|
3230
|
+
* @param root - the document
|
|
3231
|
+
* @returns the block's text
|
|
3232
|
+
*/
|
|
3233
|
+
function blockOf(root) {
|
|
3234
|
+
return isJsonObject(root) && typeof root[STYLE_BLOCK_NAME] === "string" ? root[STYLE_BLOCK_NAME] : null;
|
|
3235
|
+
}
|
|
3074
3236
|
/**
|
|
3075
3237
|
* Whether a Cytoscape element's position has a numeric z.
|
|
3076
3238
|
* @param element - the element
|
|
@@ -3165,6 +3327,7 @@ export const jsonImporter = Object.freeze({
|
|
|
3165
3327
|
"typedefs",
|
|
3166
3328
|
]),
|
|
3167
3329
|
extensions: Object.freeze([".json"]),
|
|
3330
|
+
positions: jsonPositions,
|
|
3168
3331
|
mimeTypes: Object.freeze(["application/json"]),
|
|
3169
3332
|
/**
|
|
3170
3333
|
* Confidence that the head is a JSON graph document: 0 unless it starts with `{` or `[`, 0.5
|
|
@@ -3198,7 +3361,7 @@ export const jsonImporter = Object.freeze({
|
|
|
3198
3361
|
const report = new ImportReportBuilder("json", resolved.errorLimit);
|
|
3199
3362
|
const text = await readText(input, report, { ...resolved, bomlessUtf16: true });
|
|
3200
3363
|
const { root, dialect } = documentOf(parseDocument(text, report), json, report);
|
|
3201
|
-
readGraph(root, dialect, sink, report, resolved, json, options);
|
|
3364
|
+
readGraph({ root, dialect, text }, sink, report, resolved, json, options);
|
|
3202
3365
|
return report.finish();
|
|
3203
3366
|
},
|
|
3204
3367
|
/**
|
|
@@ -3235,28 +3398,41 @@ export const jsonImporter = Object.freeze({
|
|
|
3235
3398
|
const reports = [];
|
|
3236
3399
|
for (let i = 0; i < Math.max(graphs, 1); i++) {
|
|
3237
3400
|
const report = i === 0 ? first : new ImportReportBuilder("json", resolved.errorLimit);
|
|
3238
|
-
readGraph(root, dialect, sinkFor(i), report, resolved, { ...json, graphIndex: i, all: true }, options);
|
|
3401
|
+
readGraph({ root, dialect, text }, sinkFor(i), report, resolved, { ...json, graphIndex: i, all: true }, options);
|
|
3239
3402
|
reports.push(report.finish());
|
|
3240
3403
|
}
|
|
3241
3404
|
return reports;
|
|
3242
3405
|
},
|
|
3406
|
+
/**
|
|
3407
|
+
* The document's styles, read by its dialect's reader (Cytoscape.js stylesheets, graphology and vis.js keys,
|
|
3408
|
+
* NetworkX's defaults); a `graphty.styles` block gives back the rules graphty wrote.
|
|
3409
|
+
* @param snapshot - the graph the import built
|
|
3410
|
+
* @param context - the work budget and what the import kept
|
|
3411
|
+
* @returns the styles, or null when the dialect has none
|
|
3412
|
+
*/
|
|
3413
|
+
styles: jsonStyles,
|
|
3243
3414
|
});
|
|
3244
3415
|
/**
|
|
3245
3416
|
* Read one graph of a parsed document into a sink.
|
|
3246
|
-
* @param
|
|
3247
|
-
* @param
|
|
3417
|
+
* @param doc - the parsed document, its dialect and its text
|
|
3418
|
+
* @param doc.root - the parsed document
|
|
3419
|
+
* @param doc.dialect - its dialect
|
|
3420
|
+
* @param doc.text - the document's text
|
|
3248
3421
|
* @param sink - the sink
|
|
3249
3422
|
* @param report - the graph's report
|
|
3250
3423
|
* @param resolved - the resolved common options
|
|
3251
3424
|
* @param json - the resolved JSON options (graphIndex picks the JGF graph)
|
|
3252
3425
|
* @param options - the caller's options, for the sink and unused-option checks
|
|
3253
3426
|
*/
|
|
3254
|
-
function readGraph(
|
|
3427
|
+
function readGraph(doc, sink, report, resolved, json, options) {
|
|
3428
|
+
const { root, dialect, text } = doc;
|
|
3255
3429
|
const ctx = new ImportContext(sink, report, resolved, json, options?.defaultDirected !== undefined);
|
|
3430
|
+
ctx.text = text;
|
|
3256
3431
|
// the obographs reader refuses missing endpoints itself, so addMissingNodes false holds on any sink
|
|
3257
3432
|
reportSinkOptions(sink, options, report, dialect === "obographs");
|
|
3258
3433
|
reportUnusedOptions(options, report, USED_OPTIONS);
|
|
3259
3434
|
readDialect(ctx, root, dialect);
|
|
3435
|
+
report.keepForStyles(ctx.styleSource ?? { dialect, block: blockOf(root) });
|
|
3260
3436
|
ctx.reportDangling();
|
|
3261
3437
|
ctx.nodes.reportNullOnly();
|
|
3262
3438
|
ctx.edges.reportNullOnly();
|