@graphty/graph-io 0.3.43 → 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-RVtXVetw.js → exporter-quPUCBiC.js} +1805 -287
- 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 +292 -412
- 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 +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 +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 +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 +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-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
|
@@ -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
|
}
|
|
@@ -1352,9 +1394,15 @@ function reportUnreadKeys(ctx, record, known, prefix) {
|
|
|
1352
1394
|
}
|
|
1353
1395
|
}
|
|
1354
1396
|
/** The keys of a vis.js document the reader reads. */
|
|
1355
|
-
const VIS_DOCUMENT_KEYS = new Set(["nodes", "edges"]);
|
|
1397
|
+
const VIS_DOCUMENT_KEYS = new Set(["nodes", "edges", STYLE_BLOCK_NAME]);
|
|
1356
1398
|
/** The keys of a graphology serialization the reader reads. */
|
|
1357
|
-
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
|
+
]);
|
|
1358
1406
|
/** The keys of a JGF graph object the reader reads. */
|
|
1359
1407
|
const JGF_GRAPH_KEYS = new Set([
|
|
1360
1408
|
"id",
|
|
@@ -1393,94 +1441,33 @@ function isIndexBelow(value, bound) {
|
|
|
1393
1441
|
*/
|
|
1394
1442
|
function importNodeLink(ctx, root, dialect) {
|
|
1395
1443
|
const { report, json } = ctx;
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
edgesKey = hasKey(root, "edges") || !hasKey(root, "links") ? "edges" : "links";
|
|
1399
|
-
}
|
|
1400
|
-
const nodes = arraySection(root.nodes, "nodes", report);
|
|
1401
|
-
const edges = arraySection(root[edgesKey], edgesKey, report);
|
|
1402
|
-
if (nodes === null) {
|
|
1403
|
-
report.warning("missing-value", JSON_ISSUE.MISSING_SECTION, "the document has no nodes array; nodes come from the edges", { element: "nodes" });
|
|
1404
|
-
ctx.nodesFromEdges = true;
|
|
1405
|
-
}
|
|
1406
|
-
if (edges === null) {
|
|
1407
|
-
report.warning("missing-value", JSON_ISSUE.MISSING_SECTION, `the document has no ${edgesKey} array; the graph has no edges`, { element: edgesKey });
|
|
1408
|
-
}
|
|
1444
|
+
const edgesKey = json.edgesKey ?? (hasKey(root, "edges") || !hasKey(root, "links") ? "edges" : "links");
|
|
1445
|
+
const { nodeList, edgeList } = nodeLinkSections(ctx, root, edgesKey);
|
|
1409
1446
|
const directed = flagOf(root.directed, "directed", ctx.defaultDirected(dialect), report);
|
|
1410
1447
|
const multigraph = hasKey(root, "multigraph") ? flagOf(root.multigraph, "multigraph", false, report) : null;
|
|
1411
1448
|
ctx.setHeader(directed);
|
|
1412
1449
|
ctx.writeGraphDict(root.graph, "graph");
|
|
1413
|
-
reportUnreadKeys(ctx, root, new Set(["nodes", edgesKey, "directed", "multigraph", "graph"]), "");
|
|
1414
|
-
|
|
1415
|
-
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 };
|
|
1416
1454
|
ctx.sink.reserve(nodeList.length, edgeList.length);
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
let { nodeIdKey } = json;
|
|
1420
|
-
let positional = ctx.options.nodeIdFrom === "index";
|
|
1421
|
-
if (!positional && nodeIdKey === null) {
|
|
1422
|
-
const candidates = ctx.options.nodeIdFrom === "label" ? ["label", "name", "id"] : ["id", "name"];
|
|
1423
|
-
nodeIdKey = candidates.find((key) => anyHas(nodeList, key)) ?? null;
|
|
1424
|
-
if (ctx.options.nodeIdFrom === "label" && (nodeIdKey === "id" || nodeIdKey === "name")) {
|
|
1425
|
-
report.warning("unsupported", JSON_ISSUE.OPTION_IGNORED, nodeIdKey === "id"
|
|
1426
|
-
? 'nodeIdFrom "label": no node has a label or name key; ids are read from "id"'
|
|
1427
|
-
: 'nodeIdFrom "label": no node has a "label" key; ids are read from "name"', { element: "nodeIdFrom" });
|
|
1428
|
-
}
|
|
1429
|
-
if (nodeIdKey === null) {
|
|
1430
|
-
if (nodeList.length > 0) {
|
|
1431
|
-
positional = true;
|
|
1432
|
-
report.warning("missing-value", JSON_ISSUE.POSITIONAL_NODES, "no node has an id or name key; array positions are the node ids", { element: "nodes" });
|
|
1433
|
-
}
|
|
1434
|
-
else {
|
|
1435
|
-
nodeIdKey = "id";
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
if (positional) {
|
|
1440
|
-
nodeIdKey = null;
|
|
1441
|
-
}
|
|
1455
|
+
const nodeIdKey = nodeLinkIdKey(ctx, nodeList);
|
|
1456
|
+
const positional = nodeIdKey === null;
|
|
1442
1457
|
let indexLinks;
|
|
1443
1458
|
if (positional) {
|
|
1444
1459
|
indexLinks = true;
|
|
1445
1460
|
}
|
|
1446
1461
|
else if (json.indexLinks === "auto") {
|
|
1447
|
-
indexLinks =
|
|
1462
|
+
indexLinks = looksIndexLinked(nodeList, edgeList, nodeIdKey, json);
|
|
1448
1463
|
}
|
|
1449
1464
|
else {
|
|
1450
1465
|
({ indexLinks } = json);
|
|
1451
1466
|
}
|
|
1452
|
-
|
|
1453
|
-
if (indexLinks && !positional && json.indexLinks === "auto" && nodeIdKey !== null) {
|
|
1467
|
+
if (indexLinks && !positional && json.indexLinks === "auto") {
|
|
1454
1468
|
reportAmbiguousIndexLinks(ctx, nodeList, edgeList, nodeIdKey);
|
|
1455
1469
|
}
|
|
1456
|
-
|
|
1457
|
-
const element = `nodes[${i}]`;
|
|
1458
|
-
const record = nodeList[i];
|
|
1459
|
-
let pushed = null;
|
|
1460
|
-
if (!isJsonObject(record)) {
|
|
1461
|
-
ctx.badElement("node", element);
|
|
1462
|
-
}
|
|
1463
|
-
else {
|
|
1464
|
-
let id;
|
|
1465
|
-
if (nodeIdKey === null) {
|
|
1466
|
-
id = i;
|
|
1467
|
-
}
|
|
1468
|
-
else {
|
|
1469
|
-
id = ctx.coerceId(hasKey(record, nodeIdKey) ? record[nodeIdKey] : undefined, element);
|
|
1470
|
-
}
|
|
1471
|
-
if (id === null) {
|
|
1472
|
-
ctx.countSkipped("node");
|
|
1473
|
-
}
|
|
1474
|
-
else {
|
|
1475
|
-
const index = ctx.pushNode(id, element);
|
|
1476
|
-
if (index >= 0) {
|
|
1477
|
-
pushed = id;
|
|
1478
|
-
writeFlat(ctx.nodes, index, record, id, (key) => key !== nodeIdKey);
|
|
1479
|
-
}
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
positionIds?.push(pushed);
|
|
1483
|
-
}
|
|
1470
|
+
const positionIds = importNodeLinkNodes(ctx, nodeList, nodeIdKey, indexLinks);
|
|
1484
1471
|
throwIfAborted(ctx.options.signal);
|
|
1485
1472
|
const endpointKeys = importNodeLinkEdges(ctx, edgeList, edgesKey, positionIds, multigraph);
|
|
1486
1473
|
ctx.setMeta({
|
|
@@ -1492,6 +1479,103 @@ function importNodeLink(ctx, root, dialect) {
|
|
|
1492
1479
|
targetKey: endpointKeys.target ?? undefined,
|
|
1493
1480
|
}, { declaredMultigraph: multigraph, ...ctx.weightOriginPatch() });
|
|
1494
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
|
+
}
|
|
1495
1579
|
/**
|
|
1496
1580
|
* Read the node-link / d3 edge records: endpoints by id or array position, the weight, the other
|
|
1497
1581
|
* keys as attributes.
|
|
@@ -1770,6 +1854,7 @@ function importVis(ctx, root) {
|
|
|
1770
1854
|
if (arrows > 0) {
|
|
1771
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" });
|
|
1772
1856
|
}
|
|
1857
|
+
ctx.styleSource = { dialect: "vis", block: blockOf(root), options: root.options, groups: root.groups };
|
|
1773
1858
|
ctx.setMeta({ dialect: "vis", nodeIdKey, sourceKey: sourceKey ?? undefined, targetKey: targetKey ?? undefined }, ctx.weightOriginPatch());
|
|
1774
1859
|
}
|
|
1775
1860
|
// ============================================================ NetworkX adjacency_data / tree_data
|
|
@@ -2083,36 +2168,29 @@ function importGraphology(ctx, root) {
|
|
|
2083
2168
|
});
|
|
2084
2169
|
}
|
|
2085
2170
|
const type = graphologyType(ctx, options);
|
|
2086
|
-
ctx.setHeader(
|
|
2171
|
+
ctx.setHeader(type === "mixed" ? mostlyDirected(ctx, edges) : type === "directed");
|
|
2087
2172
|
const multi = hasKey(options, "multi") ? flagOf(options.multi, "options.multi", false, report) : null;
|
|
2088
2173
|
const allowSelfLoops = hasKey(options, "allowSelfLoops")
|
|
2089
2174
|
? flagOf(options.allowSelfLoops, "options.allowSelfLoops", true, report)
|
|
2090
2175
|
: undefined;
|
|
2091
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 };
|
|
2092
2182
|
ctx.reportNodeIdFrom("graphology", "the node key");
|
|
2093
2183
|
ctx.sink.reserve(nodes.length, edges.length);
|
|
2094
|
-
|
|
2095
|
-
pushGraphologyNode(ctx, nodes[i], `nodes[${i}]`);
|
|
2096
|
-
}
|
|
2184
|
+
importGraphologyNodes(ctx, nodes, gephi);
|
|
2097
2185
|
throwIfAborted(ctx.options.signal);
|
|
2098
|
-
const
|
|
2099
|
-
|
|
2100
|
-
type,
|
|
2101
|
-
allowSelfLoops,
|
|
2102
|
-
// what the edges do against the declared options: graphology itself refuses such a document
|
|
2103
|
-
violations: { selfLoops: 0, parallels: 0, flags: 0 },
|
|
2104
|
-
pairs: multi === false ? new Set() : null,
|
|
2105
|
-
};
|
|
2106
|
-
for (let i = 0; i < edges.length; i++) {
|
|
2107
|
-
readGraphologyEdge(ctx, reading, edges[i], `edges[${i}]`);
|
|
2108
|
-
}
|
|
2109
|
-
reportGraphologyViolations(ctx, reading.violations, type);
|
|
2186
|
+
const violations = importGraphologyEdges(ctx, edges, { type, gephi, multi, allowSelfLoops });
|
|
2187
|
+
reportGraphologyViolations(ctx, violations, type);
|
|
2110
2188
|
ctx.setMeta({ dialect: "graphology", allowSelfLoops }, { declaredMultigraph: multi, ...ctx.weightOriginPatch() });
|
|
2111
2189
|
}
|
|
2112
2190
|
/**
|
|
2113
|
-
* A graphology document's `options.type
|
|
2191
|
+
* A graphology document's `options.type`: "mixed" when absent or not one of the three (reported).
|
|
2114
2192
|
* @param ctx - the context
|
|
2115
|
-
* @param options - the options
|
|
2193
|
+
* @param options - the document's options
|
|
2116
2194
|
* @returns the type
|
|
2117
2195
|
*/
|
|
2118
2196
|
function graphologyType(ctx, options) {
|
|
@@ -2125,114 +2203,133 @@ function graphologyType(ctx, options) {
|
|
|
2125
2203
|
return "mixed";
|
|
2126
2204
|
}
|
|
2127
2205
|
/**
|
|
2128
|
-
* The header direction of a graphology
|
|
2129
|
-
* 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.
|
|
2130
2207
|
* @param ctx - the context
|
|
2131
|
-
* @param type - options.type
|
|
2132
2208
|
* @param edges - the edge records
|
|
2133
|
-
* @returns
|
|
2209
|
+
* @returns true for directed
|
|
2134
2210
|
*/
|
|
2135
|
-
function
|
|
2136
|
-
if (type !== "mixed") {
|
|
2137
|
-
return type === "directed";
|
|
2138
|
-
}
|
|
2211
|
+
function mostlyDirected(ctx, edges) {
|
|
2139
2212
|
const objects = edges.filter((edge) => isJsonObject(edge));
|
|
2140
2213
|
const undirectedEdges = objects.filter((edge) => edge.undirected === true).length;
|
|
2141
2214
|
return objects.length === 0 ? ctx.defaultDirected("graphology") : undirectedEdges < objects.length;
|
|
2142
2215
|
}
|
|
2143
2216
|
/**
|
|
2144
|
-
*
|
|
2217
|
+
* Read the graphology node records.
|
|
2145
2218
|
* @param ctx - the context
|
|
2146
|
-
* @param
|
|
2147
|
-
* @param
|
|
2219
|
+
* @param nodes - the node records
|
|
2220
|
+
* @param gephi - whether Gephi wrote them (ids under `id`, display keys beside the attributes)
|
|
2148
2221
|
*/
|
|
2149
|
-
function
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
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);
|
|
2158
2237
|
}
|
|
2159
|
-
pushNestedNode(ctx, id, record, "attributes", GRAPHOLOGY_NODE_KEYS, element);
|
|
2160
2238
|
}
|
|
2161
2239
|
/**
|
|
2162
|
-
* Read
|
|
2240
|
+
* Read the graphology edge records.
|
|
2163
2241
|
* @param ctx - the context
|
|
2164
|
-
* @param
|
|
2165
|
-
* @param
|
|
2166
|
-
* @
|
|
2167
|
-
*/
|
|
2168
|
-
function
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
const u = ctx.coerceId(record.source, `${element}.source`);
|
|
2179
|
-
const v = ctx.coerceId(record.target, `${element}.target`);
|
|
2180
|
-
if (u === null || v === null) {
|
|
2181
|
-
ctx.countSkipped("edge");
|
|
2182
|
-
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;
|
|
2183
2256
|
}
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
if (reading.allowSelfLoops === false && u === v) {
|
|
2191
|
-
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
|
+
}
|
|
2192
2263
|
}
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
reading.violations.parallels += reading.pairs.has(pair) ? 1 : 0;
|
|
2196
|
-
reading.pairs.add(pair);
|
|
2264
|
+
catch (err) {
|
|
2265
|
+
ctx.skip(err, "edge", element);
|
|
2197
2266
|
}
|
|
2198
2267
|
}
|
|
2199
|
-
|
|
2200
|
-
ctx.skip(err, "edge", element);
|
|
2201
|
-
}
|
|
2268
|
+
return violations;
|
|
2202
2269
|
}
|
|
2203
2270
|
/**
|
|
2204
|
-
*
|
|
2205
|
-
* (a contrary flag is counted as a violation).
|
|
2271
|
+
* One graphology edge record, when it is an object with both endpoints.
|
|
2206
2272
|
* @param ctx - the context
|
|
2207
|
-
* @param reading - the read's state
|
|
2208
2273
|
* @param record - the edge record
|
|
2209
2274
|
* @param element - the element name
|
|
2210
|
-
* @returns the
|
|
2275
|
+
* @returns the record, or null when it was reported and is skipped
|
|
2211
2276
|
*/
|
|
2212
|
-
function
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
return
|
|
2277
|
+
function graphologyEdgeRecord(ctx, record, element) {
|
|
2278
|
+
if (!isJsonObject(record)) {
|
|
2279
|
+
ctx.badElement("edge", element);
|
|
2280
|
+
return null;
|
|
2216
2281
|
}
|
|
2217
|
-
if (
|
|
2218
|
-
|
|
2282
|
+
if (!present(record, "source") || !present(record, "target")) {
|
|
2283
|
+
ctx.missingEndpoint(element, present(record, "source") ? "target" : "source");
|
|
2284
|
+
return null;
|
|
2219
2285
|
}
|
|
2220
|
-
return
|
|
2286
|
+
return record;
|
|
2221
2287
|
}
|
|
2222
2288
|
/**
|
|
2223
|
-
*
|
|
2224
|
-
* no attributes.
|
|
2289
|
+
* Add one graphology edge with its id and attributes.
|
|
2225
2290
|
* @param ctx - the context
|
|
2226
2291
|
* @param record - the edge record
|
|
2227
2292
|
* @param element - the element name
|
|
2228
|
-
* @
|
|
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
|
|
2229
2297
|
*/
|
|
2230
|
-
function
|
|
2231
|
-
const {
|
|
2232
|
-
|
|
2233
|
-
|
|
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";
|
|
2234
2310
|
}
|
|
2235
|
-
|
|
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")}`;
|
|
2236
2333
|
}
|
|
2237
2334
|
/**
|
|
2238
2335
|
* Report the edges that contradict a graphology document's declared options (W_JSON_INCONSISTENT,
|
|
@@ -2270,9 +2367,10 @@ function reportGraphologyViolations(ctx, violations, type) {
|
|
|
2270
2367
|
* @param dictKey - the key of the nested dict
|
|
2271
2368
|
* @param structural - the element keys that are not attributes
|
|
2272
2369
|
* @param element - the element name
|
|
2370
|
+
* @param plain - write the element-level keys under their own names
|
|
2273
2371
|
* @returns the node index, or -1 when skipped
|
|
2274
2372
|
*/
|
|
2275
|
-
function pushNestedNode(ctx, id, record, dictKey, structural, element) {
|
|
2373
|
+
function pushNestedNode(ctx, id, record, dictKey, structural, element, plain = false) {
|
|
2276
2374
|
const index = ctx.pushNode(id, element);
|
|
2277
2375
|
if (index < 0) {
|
|
2278
2376
|
return index;
|
|
@@ -2282,7 +2380,7 @@ function pushNestedNode(ctx, id, record, dictKey, structural, element) {
|
|
|
2282
2380
|
if (dict !== undefined && dict !== null && !isJsonObject(dict)) {
|
|
2283
2381
|
ctx.report.error("validation-error", JSON_ISSUE.BAD_VALUE, `${element}: ${dictKey} must be an object, found ${describe(dict)}`, { element });
|
|
2284
2382
|
}
|
|
2285
|
-
ctx.writeNested(ctx.nodes, index, record, isJsonObject(dict) ? dict : {}, structural,
|
|
2383
|
+
ctx.writeNested(ctx.nodes, index, record, isJsonObject(dict) ? dict : {}, structural, element, { plain });
|
|
2286
2384
|
}
|
|
2287
2385
|
catch (err) {
|
|
2288
2386
|
ctx.report.recordError(err, { element: String(id) });
|
|
@@ -2320,7 +2418,7 @@ function importJgf(ctx, root) {
|
|
|
2320
2418
|
ctx.sink.reserve(nodeRecords.length, edges.length);
|
|
2321
2419
|
const labelColumn = ctx.nodes.declareIf({ name: "label", dtype: "string", role: "label", nullable: true }, anyHas(nodeRecords, "label"));
|
|
2322
2420
|
if (isJsonObject(nodesRaw)) {
|
|
2323
|
-
for (const key of
|
|
2421
|
+
for (const key of jgfNodeKeys(ctx, root, graph, nodesRaw)) {
|
|
2324
2422
|
pushJgfKeyedNode(ctx, key, nodesRaw[key], labelColumn);
|
|
2325
2423
|
}
|
|
2326
2424
|
}
|
|
@@ -2426,7 +2524,7 @@ function jgfEdgeWriter(ctx, edges, hyperedges) {
|
|
|
2426
2524
|
element,
|
|
2427
2525
|
});
|
|
2428
2526
|
}
|
|
2429
|
-
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 });
|
|
2430
2528
|
};
|
|
2431
2529
|
}
|
|
2432
2530
|
/**
|
|
@@ -2460,6 +2558,25 @@ function readJgfEdge(ctx, record, element, directed, writeJgfEdge) {
|
|
|
2460
2558
|
ctx.skip(err, "edge", element);
|
|
2461
2559
|
}
|
|
2462
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
|
+
}
|
|
2463
2580
|
/**
|
|
2464
2581
|
* The graph object of a JGF document: `graph`, or the graph of `graphs` that graphIndex /
|
|
2465
2582
|
* graphName choose (chooseGraph()).
|
|
@@ -2613,7 +2730,7 @@ function pushJgfNode(ctx, id, record, labelColumn, element) {
|
|
|
2613
2730
|
element,
|
|
2614
2731
|
});
|
|
2615
2732
|
}
|
|
2616
|
-
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);
|
|
2617
2734
|
}
|
|
2618
2735
|
catch (err) {
|
|
2619
2736
|
ctx.report.recordError(err, { element: String(id) });
|
|
@@ -2768,42 +2885,44 @@ function distinctMembers(ctx, members, element) {
|
|
|
2768
2885
|
function importCytoscape(ctx, root) {
|
|
2769
2886
|
const { elements, extra } = cytoscapeRoot(ctx, root);
|
|
2770
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
|
+
};
|
|
2771
2897
|
ctx.setHeader(ctx.defaultDirected("cytoscape"));
|
|
2772
2898
|
ctx.reportNodeIdFrom("cytoscape", "data.id");
|
|
2773
2899
|
ctx.sink.reserve(nodes.length, edges.length);
|
|
2774
|
-
const
|
|
2775
|
-
const reading = {
|
|
2776
|
-
positionColumn: ctx.nodes.declareIf({
|
|
2777
|
-
name: POSITION_COLUMN,
|
|
2778
|
-
dtype: "f64",
|
|
2779
|
-
components: 3,
|
|
2780
|
-
role: "position",
|
|
2781
|
-
mutable: true,
|
|
2782
|
-
nullable: true,
|
|
2783
|
-
// 3D layouts written by Cytoscape-compatible tools carry a z
|
|
2784
|
-
extra: { sourceDims: nodes.some(hasPositionZ) ? 3 : 2, units: "file" },
|
|
2785
|
-
origin: { format: "json", namespace: "cytoscape" },
|
|
2786
|
-
}, anyHas(nodes, "position")),
|
|
2787
|
-
classesColumn: ctx.nodes.declareIf({ name: CLASSES_COLUMN, dtype: "list", itemDtype: "string", role: "classes", nullable: true }, anyHas(nodes, "classes")),
|
|
2788
|
-
parents: [],
|
|
2789
|
-
point: [0, 0, 0],
|
|
2790
|
-
};
|
|
2791
|
-
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);
|
|
2792
2901
|
const edgeClassesColumn = ctx.edges.declareIf({ name: CLASSES_COLUMN, dtype: "list", itemDtype: "string", role: "classes", nullable: true }, anyHas(edges, "classes"));
|
|
2902
|
+
const parents = [];
|
|
2793
2903
|
for (let i = 0; i < nodes.length; i++) {
|
|
2794
|
-
|
|
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
|
+
}
|
|
2795
2914
|
}
|
|
2796
|
-
resolveCytoscapeParents(ctx,
|
|
2915
|
+
resolveCytoscapeParents(ctx, parents, columns.parent);
|
|
2797
2916
|
throwIfAborted(ctx.options.signal);
|
|
2798
2917
|
importCytoscapeEdges(ctx, edges, edgeClassesColumn);
|
|
2799
2918
|
ctx.setMeta({ dialect: "cytoscape", cytoscape: extra }, ctx.weightOriginPatch());
|
|
2800
2919
|
}
|
|
2801
2920
|
/**
|
|
2802
|
-
*
|
|
2803
|
-
*
|
|
2921
|
+
* A Cytoscape document's elements, and its other top-level keys (kept in meta); its `data` is written as graph
|
|
2922
|
+
* attributes.
|
|
2804
2923
|
* @param ctx - the context
|
|
2805
|
-
* @param root - the document
|
|
2806
|
-
* @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)
|
|
2807
2926
|
*/
|
|
2808
2927
|
function cytoscapeRoot(ctx, root) {
|
|
2809
2928
|
if (Array.isArray(root)) {
|
|
@@ -2812,31 +2931,53 @@ function cytoscapeRoot(ctx, root) {
|
|
|
2812
2931
|
if (!isJsonObject(root)) {
|
|
2813
2932
|
ctx.report.fail(JSON_ISSUE.SHAPE, `a Cytoscape document must be an object or an array, found ${describe(root)}`);
|
|
2814
2933
|
}
|
|
2815
|
-
|
|
2934
|
+
const object = root;
|
|
2935
|
+
ctx.writeGraphDict(object.data, "data");
|
|
2816
2936
|
const rest = {};
|
|
2817
|
-
for (const key of Object.keys(
|
|
2818
|
-
if (key !== "elements" && key !== "data") {
|
|
2819
|
-
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];
|
|
2820
2940
|
}
|
|
2821
2941
|
}
|
|
2822
|
-
return Object.keys(rest).length > 0 ? { elements:
|
|
2942
|
+
return Object.keys(rest).length > 0 ? { elements: object.elements, extra: rest } : { elements: object.elements };
|
|
2823
2943
|
}
|
|
2824
2944
|
/**
|
|
2825
|
-
*
|
|
2826
|
-
*
|
|
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.
|
|
2827
2970
|
* @param ctx - the context
|
|
2828
|
-
* @param reading - the read's state
|
|
2829
2971
|
* @param record - the element
|
|
2972
|
+
* @param data - its data object
|
|
2973
|
+
* @param raw - its raw id
|
|
2830
2974
|
* @param element - the element name
|
|
2975
|
+
* @param columns - the node columns
|
|
2976
|
+
* @param parents - receives its parent link
|
|
2831
2977
|
*/
|
|
2832
|
-
function
|
|
2978
|
+
function importCytoscapeNode(ctx, record, data, raw, element, columns, parents) {
|
|
2833
2979
|
const { report } = ctx;
|
|
2834
|
-
|
|
2835
|
-
ctx.badElement("node", element, "an element with a data object");
|
|
2836
|
-
return;
|
|
2837
|
-
}
|
|
2838
|
-
const { data } = record;
|
|
2839
|
-
const id = ctx.coerceId(hasKey(data, "id") ? data.id : undefined, element);
|
|
2980
|
+
const id = ctx.coerceId(raw, element);
|
|
2840
2981
|
if (id === null) {
|
|
2841
2982
|
ctx.countSkipped("node");
|
|
2842
2983
|
return;
|
|
@@ -2849,9 +2990,18 @@ function readCytoscapeNode(ctx, reading, record, element) {
|
|
|
2849
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 });
|
|
2850
2991
|
}
|
|
2851
2992
|
try {
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
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);
|
|
2855
3005
|
writeElementKeys(ctx.nodes, index, record, element);
|
|
2856
3006
|
}
|
|
2857
3007
|
catch (err) {
|
|
@@ -2859,53 +3009,21 @@ function readCytoscapeNode(ctx, reading, record, element) {
|
|
|
2859
3009
|
}
|
|
2860
3010
|
}
|
|
2861
3011
|
/**
|
|
2862
|
-
* Write a Cytoscape node's
|
|
2863
|
-
*
|
|
2864
|
-
* @param reading - the read's state
|
|
2865
|
-
* @param index - the node index
|
|
2866
|
-
* @param data - the element's data object
|
|
2867
|
-
* @param element - the element name
|
|
2868
|
-
*/
|
|
2869
|
-
function writeCytoscapeData(ctx, reading, index, data, element) {
|
|
2870
|
-
for (const key of Object.keys(data)) {
|
|
2871
|
-
if (key === "id") {
|
|
2872
|
-
continue;
|
|
2873
|
-
}
|
|
2874
|
-
if (key !== "parent") {
|
|
2875
|
-
ctx.nodes.write(index, key, data[key], SUFFIX.data, element);
|
|
2876
|
-
continue;
|
|
2877
|
-
}
|
|
2878
|
-
const raw = data.parent;
|
|
2879
|
-
if (raw === undefined || raw === null) {
|
|
2880
|
-
continue;
|
|
2881
|
-
}
|
|
2882
|
-
const parent = ctx.coerceId(raw, `${element}.data.parent`);
|
|
2883
|
-
if (parent !== null) {
|
|
2884
|
-
reading.parents.push({ index, parent, element });
|
|
2885
|
-
}
|
|
2886
|
-
}
|
|
2887
|
-
}
|
|
2888
|
-
/**
|
|
2889
|
-
* Write a Cytoscape node's `position` ({ x, y, z? }, y flipped to grow upward); any other value is
|
|
2890
|
-
* 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).
|
|
2891
3014
|
* @param ctx - the context
|
|
2892
|
-
* @param
|
|
2893
|
-
* @param index - the node
|
|
3015
|
+
* @param column - the position column
|
|
3016
|
+
* @param index - the node
|
|
2894
3017
|
* @param position - the element's position
|
|
2895
3018
|
* @param element - the element name
|
|
2896
3019
|
*/
|
|
2897
|
-
function writeCytoscapePosition(ctx,
|
|
3020
|
+
function writeCytoscapePosition(ctx, column, index, position, element) {
|
|
2898
3021
|
if (position === undefined || position === null) {
|
|
2899
3022
|
return;
|
|
2900
3023
|
}
|
|
2901
3024
|
const z = isJsonObject(position) ? (position.z ?? 0) : 0;
|
|
2902
3025
|
if (isJsonObject(position) && isCoordinate(position.x) && isCoordinate(position.y) && isCoordinate(z)) {
|
|
2903
|
-
|
|
2904
|
-
point[0] = position.x;
|
|
2905
|
-
// Cytoscape's y grows downward; positions are stored y-up (the exporter flips back)
|
|
2906
|
-
point[1] = flipY(position.y);
|
|
2907
|
-
point[2] = z;
|
|
2908
|
-
ctx.nodes.set(reading.positionColumn, index, point);
|
|
3026
|
+
ctx.nodes.set(column, index, [position.x, flipY(position.y), z]);
|
|
2909
3027
|
}
|
|
2910
3028
|
else {
|
|
2911
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 });
|
|
@@ -2924,7 +3042,11 @@ function resolveCytoscapeParents(ctx, parents, parentColumn) {
|
|
|
2924
3042
|
// the last link per child (a duplicate node's later parent wins), child -> its link
|
|
2925
3043
|
const linkOf = new Map();
|
|
2926
3044
|
for (let order = 0; order < parents.length; order++) {
|
|
2927
|
-
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
|
+
}
|
|
2928
3050
|
const parentIndex = ctx.sink.indexOf(parent);
|
|
2929
3051
|
if (parentIndex === INVALID_INDEX) {
|
|
2930
3052
|
report.error("missing-value", JSON_ISSUE.UNKNOWN_PARENT, `${element}: parent ${JSON.stringify(parent)} is not a node`, { element });
|
|
@@ -3015,8 +3137,8 @@ function importCytoscapeEdges(ctx, edges, edgeClassesColumn) {
|
|
|
3015
3137
|
function importCytoscapeEdge(ctx, shared, record, data, element) {
|
|
3016
3138
|
const { ids, kind, edgeClassesColumn } = shared;
|
|
3017
3139
|
try {
|
|
3018
|
-
const u = ctx.
|
|
3019
|
-
const v = ctx.
|
|
3140
|
+
const u = ctx.textualId(data.source, `${element}.data.source`);
|
|
3141
|
+
const v = ctx.textualId(data.target, `${element}.data.target`);
|
|
3020
3142
|
if (u === null || v === null) {
|
|
3021
3143
|
ctx.countSkipped("edge");
|
|
3022
3144
|
return;
|
|
@@ -3072,6 +3194,45 @@ function cytoscapeSections(ctx, elements) {
|
|
|
3072
3194
|
}
|
|
3073
3195
|
return report.fail(JSON_ISSUE.SHAPE, `elements must be an object or an array, found ${describe(elements)}`);
|
|
3074
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
|
+
}
|
|
3075
3236
|
/**
|
|
3076
3237
|
* Whether a Cytoscape element's position has a numeric z.
|
|
3077
3238
|
* @param element - the element
|
|
@@ -3166,6 +3327,7 @@ export const jsonImporter = Object.freeze({
|
|
|
3166
3327
|
"typedefs",
|
|
3167
3328
|
]),
|
|
3168
3329
|
extensions: Object.freeze([".json"]),
|
|
3330
|
+
positions: jsonPositions,
|
|
3169
3331
|
mimeTypes: Object.freeze(["application/json"]),
|
|
3170
3332
|
/**
|
|
3171
3333
|
* Confidence that the head is a JSON graph document: 0 unless it starts with `{` or `[`, 0.5
|
|
@@ -3199,7 +3361,7 @@ export const jsonImporter = Object.freeze({
|
|
|
3199
3361
|
const report = new ImportReportBuilder("json", resolved.errorLimit);
|
|
3200
3362
|
const text = await readText(input, report, { ...resolved, bomlessUtf16: true });
|
|
3201
3363
|
const { root, dialect } = documentOf(parseDocument(text, report), json, report);
|
|
3202
|
-
readGraph(root, dialect, sink, report, resolved, json, options);
|
|
3364
|
+
readGraph({ root, dialect, text }, sink, report, resolved, json, options);
|
|
3203
3365
|
return report.finish();
|
|
3204
3366
|
},
|
|
3205
3367
|
/**
|
|
@@ -3236,28 +3398,41 @@ export const jsonImporter = Object.freeze({
|
|
|
3236
3398
|
const reports = [];
|
|
3237
3399
|
for (let i = 0; i < Math.max(graphs, 1); i++) {
|
|
3238
3400
|
const report = i === 0 ? first : new ImportReportBuilder("json", resolved.errorLimit);
|
|
3239
|
-
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);
|
|
3240
3402
|
reports.push(report.finish());
|
|
3241
3403
|
}
|
|
3242
3404
|
return reports;
|
|
3243
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,
|
|
3244
3414
|
});
|
|
3245
3415
|
/**
|
|
3246
3416
|
* Read one graph of a parsed document into a sink.
|
|
3247
|
-
* @param
|
|
3248
|
-
* @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
|
|
3249
3421
|
* @param sink - the sink
|
|
3250
3422
|
* @param report - the graph's report
|
|
3251
3423
|
* @param resolved - the resolved common options
|
|
3252
3424
|
* @param json - the resolved JSON options (graphIndex picks the JGF graph)
|
|
3253
3425
|
* @param options - the caller's options, for the sink and unused-option checks
|
|
3254
3426
|
*/
|
|
3255
|
-
function readGraph(
|
|
3427
|
+
function readGraph(doc, sink, report, resolved, json, options) {
|
|
3428
|
+
const { root, dialect, text } = doc;
|
|
3256
3429
|
const ctx = new ImportContext(sink, report, resolved, json, options?.defaultDirected !== undefined);
|
|
3430
|
+
ctx.text = text;
|
|
3257
3431
|
// the obographs reader refuses missing endpoints itself, so addMissingNodes false holds on any sink
|
|
3258
3432
|
reportSinkOptions(sink, options, report, dialect === "obographs");
|
|
3259
3433
|
reportUnusedOptions(options, report, USED_OPTIONS);
|
|
3260
3434
|
readDialect(ctx, root, dialect);
|
|
3435
|
+
report.keepForStyles(ctx.styleSource ?? { dialect, block: blockOf(root) });
|
|
3261
3436
|
ctx.reportDangling();
|
|
3262
3437
|
ctx.nodes.reportNullOnly();
|
|
3263
3438
|
ctx.edges.reportNullOnly();
|