@graphty/graph-io 0.3.48 → 0.3.50
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-C2riR4NT.js → approximations-BRXsll0T.js} +2 -2
- package/dist/chunks/{approximations-C2riR4NT.js.map → approximations-BRXsll0T.js.map} +1 -1
- package/dist/chunks/bends-BGXjv_U4.js +129 -0
- package/dist/chunks/bends-BGXjv_U4.js.map +1 -0
- package/dist/chunks/{block-Cu22ewuS.js → block-yl0f_qLO.js} +931 -164
- package/dist/chunks/block-yl0f_qLO.js.map +1 -0
- package/dist/chunks/choose-CczZJaX_.js +717 -0
- package/dist/chunks/choose-CczZJaX_.js.map +1 -0
- package/dist/chunks/{codes-CV_Bhcyi.js → codes-BE2xir2k.js} +6 -2
- package/dist/chunks/codes-BE2xir2k.js.map +1 -0
- package/dist/chunks/{constants-D0LqcsLJ.js → constants-CKkYLPtt.js} +2 -2
- package/dist/chunks/{constants-D0LqcsLJ.js.map → constants-CKkYLPtt.js.map} +1 -1
- package/dist/chunks/{context-cgmmOxZ2.js → context-DizmppHy.js} +5 -4
- package/dist/chunks/{context-cgmmOxZ2.js.map → context-DizmppHy.js.map} +1 -1
- package/dist/chunks/{convert-BcQ8_jMo.js → convert-Ct2zelbQ.js} +7 -2
- package/dist/chunks/convert-Ct2zelbQ.js.map +1 -0
- package/dist/chunks/{credentials-BiQsnMTb.js → credentials-CmvJXYeH.js} +67 -16
- package/dist/chunks/credentials-CmvJXYeH.js.map +1 -0
- package/dist/chunks/{cx-export-BEeF6ymo.js → cx-export-Bt6NoqTQ.js} +3 -3
- package/dist/chunks/{cx-export-BEeF6ymo.js.map → cx-export-Bt6NoqTQ.js.map} +1 -1
- package/dist/chunks/descriptor-B28U25x4.js +60 -0
- package/dist/chunks/descriptor-B28U25x4.js.map +1 -0
- package/dist/chunks/{descriptor-BJ-W0Jd-.js → descriptor-Dhez_Cew.js} +11 -2
- package/dist/chunks/descriptor-Dhez_Cew.js.map +1 -0
- package/dist/chunks/{emit-CD8xnY8s.js → emit-7Jkpg0yd.js} +1788 -133
- package/dist/chunks/emit-7Jkpg0yd.js.map +1 -0
- package/dist/chunks/{escape-DH2Egt-l.js → escape-CuCIzNMB.js} +8 -8
- package/dist/chunks/{escape-DH2Egt-l.js.map → escape-CuCIzNMB.js.map} +1 -1
- package/dist/chunks/{export-CZ7VRm4I.js → export-Cha4dRFz.js} +45 -387
- package/dist/chunks/export-Cha4dRFz.js.map +1 -0
- package/dist/chunks/{exporter-ChjL5fmP.js → exporter-1Ajud15J.js} +9 -8
- package/dist/chunks/{exporter-ChjL5fmP.js.map → exporter-1Ajud15J.js.map} +1 -1
- package/dist/chunks/{exporter-BIdaoIgh.js → exporter-B6yvL3wy.js} +7 -7
- package/dist/chunks/{exporter-BIdaoIgh.js.map → exporter-B6yvL3wy.js.map} +1 -1
- package/dist/chunks/{exporter-Dcw7Ldtq.js → exporter-BP6otMO6.js} +6 -6
- package/dist/chunks/{exporter-Dcw7Ldtq.js.map → exporter-BP6otMO6.js.map} +1 -1
- package/dist/chunks/{exporter-DtVU80Fa.js → exporter-CA5q8ROP.js} +9 -8
- package/dist/chunks/{exporter-DtVU80Fa.js.map → exporter-CA5q8ROP.js.map} +1 -1
- package/dist/chunks/{exporter-bxxjOrDZ.js → exporter-CQQZFJ2v.js} +1284 -156
- package/dist/chunks/exporter-CQQZFJ2v.js.map +1 -0
- package/dist/chunks/format-BXiAb-1h.js +408 -0
- package/dist/chunks/format-BXiAb-1h.js.map +1 -0
- package/dist/chunks/{generic-CP6YD34u.js → generic-Dc21MAdg.js} +387 -31
- package/dist/chunks/generic-Dc21MAdg.js.map +1 -0
- package/dist/chunks/{importer-B87_fmVx.js → importer-C6NVpCXp.js} +327 -84
- package/dist/chunks/importer-C6NVpCXp.js.map +1 -0
- package/dist/chunks/{importer-DPZDN40-.js → importer-CKFe4q54.js} +25 -17
- package/dist/chunks/importer-CKFe4q54.js.map +1 -0
- package/dist/chunks/{importer-Bji2MeWr.js → importer-CKbUbsJA.js} +13 -10
- package/dist/chunks/{importer-Bji2MeWr.js.map → importer-CKbUbsJA.js.map} +1 -1
- package/dist/chunks/{importer-CB_zV5_L.js → importer-ClCsdgTJ.js} +208 -1104
- package/dist/chunks/importer-ClCsdgTJ.js.map +1 -0
- package/dist/chunks/{importer-e3huMZbm.js → importer-CyVZTrf0.js} +14 -10
- package/dist/chunks/importer-CyVZTrf0.js.map +1 -0
- package/dist/chunks/{importer-CVT-JyDE.js → importer-DgG4v1Ms.js} +1537 -355
- package/dist/chunks/importer-DgG4v1Ms.js.map +1 -0
- package/dist/chunks/{importer-Cyy6UseH.js → importer-asFUrIsj.js} +66 -13
- package/dist/chunks/importer-asFUrIsj.js.map +1 -0
- package/dist/chunks/{input-Ccg9I22A.js → input-CAxt_aV-.js} +4 -4
- package/dist/chunks/{input-Ccg9I22A.js.map → input-CAxt_aV-.js.map} +1 -1
- package/dist/chunks/{json-elements-By172SVq.js → json-elements-Cq76WjnZ.js} +4 -4
- package/dist/chunks/{json-elements-By172SVq.js.map → json-elements-Cq76WjnZ.js.map} +1 -1
- package/dist/chunks/{lexicon-u2SI5xcx.js → lexicon-IVRq2Uoo.js} +282 -74
- package/dist/chunks/lexicon-IVRq2Uoo.js.map +1 -0
- package/dist/chunks/{ontology-export-BwgMyuF0.js → ontology-export-OMo91mb0.js} +4 -4
- package/dist/chunks/{ontology-export-BwgMyuF0.js.map → ontology-export-OMo91mb0.js.map} +1 -1
- package/dist/chunks/{records-Cgvxz-Vx.js → records-NJiYvekn.js} +2 -2
- package/dist/chunks/{records-Cgvxz-Vx.js.map → records-NJiYvekn.js.map} +1 -1
- package/dist/chunks/{report-CgdsL9Hb.js → report-CwMfYa9J.js} +23 -23
- package/dist/chunks/{report-CgdsL9Hb.js.map → report-CwMfYa9J.js.map} +1 -1
- package/dist/chunks/round-trip-Cy3_SHRZ.js +79 -0
- package/dist/chunks/round-trip-Cy3_SHRZ.js.map +1 -0
- package/dist/chunks/{sigv4-LkAzsLAu.js → sigv4-BXwVbza3.js} +5 -5
- package/dist/chunks/sigv4-BXwVbza3.js.map +1 -0
- package/dist/chunks/{styles-CaABMoO1.js → styles-CAVmBLgp.js} +1237 -138
- package/dist/chunks/styles-CAVmBLgp.js.map +1 -0
- package/dist/chunks/styles-CPczw1Jz.js +1928 -0
- package/dist/chunks/styles-CPczw1Jz.js.map +1 -0
- package/dist/chunks/styles-boK6Ln54.js +2847 -0
- package/dist/chunks/styles-boK6Ln54.js.map +1 -0
- package/dist/chunks/{styles-yed-Cs1nmrjn.js → styles-yed-XeFBQ6VS.js} +506 -175
- package/dist/chunks/styles-yed-XeFBQ6VS.js.map +1 -0
- package/dist/chunks/{text-BuKQVMz2.js → text-ystE2bYi.js} +2 -2
- package/dist/chunks/{text-BuKQVMz2.js.map → text-ystE2bYi.js.map} +1 -1
- package/dist/csv.js +7 -7
- package/dist/cx.js +2 -2
- package/dist/cx2.js +2 -2
- package/dist/cys.js +1 -1
- package/dist/dot.js +8 -4
- package/dist/dot.js.map +1 -1
- package/dist/gexf.js +42 -12
- package/dist/gexf.js.map +1 -1
- package/dist/gml.js +848 -194
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +230 -193
- package/dist/graph-io.js.map +1 -1
- package/dist/graphml.js +3 -3
- package/dist/json.js +3 -2
- package/dist/neo4j.js +6 -6
- package/dist/obo.js +1 -1
- package/dist/pajek.js +1 -1
- package/dist/positions.js +45 -3
- package/dist/positions.js.map +1 -1
- package/dist/sources-cypher.js +141 -23
- package/dist/sources-cypher.js.map +1 -1
- package/dist/sources-ndex.js +2 -2
- package/dist/sources-rest.js +32 -6
- package/dist/sources-rest.js.map +1 -1
- package/dist/sources-sparql.d.ts +1 -0
- package/dist/sources-sparql.js +439 -0
- package/dist/sources-sparql.js.map +1 -0
- package/dist/src/formats/cx/importer.d.ts.map +1 -1
- package/dist/src/formats/cx/importer.js +5 -1
- package/dist/src/formats/cx/importer.js.map +1 -1
- package/dist/src/formats/cx/styles.d.ts +24 -1
- package/dist/src/formats/cx/styles.d.ts.map +1 -1
- package/dist/src/formats/cx/styles.js +117 -11
- package/dist/src/formats/cx/styles.js.map +1 -1
- package/dist/src/formats/cx2/importer.d.ts.map +1 -1
- package/dist/src/formats/cx2/importer.js +1 -0
- package/dist/src/formats/cx2/importer.js.map +1 -1
- package/dist/src/formats/cx2/styles.d.ts.map +1 -1
- package/dist/src/formats/cx2/styles.js +3 -1
- package/dist/src/formats/cx2/styles.js.map +1 -1
- package/dist/src/formats/cys/importer.d.ts.map +1 -1
- package/dist/src/formats/cys/importer.js +1 -0
- package/dist/src/formats/cys/importer.js.map +1 -1
- package/dist/src/formats/cys/styles.d.ts +2 -0
- package/dist/src/formats/cys/styles.d.ts.map +1 -1
- package/dist/src/formats/cys/styles.js +15 -7
- package/dist/src/formats/cys/styles.js.map +1 -1
- package/dist/src/formats/dot/drawing.d.ts +98 -0
- package/dist/src/formats/dot/drawing.d.ts.map +1 -0
- package/dist/src/formats/dot/drawing.js +734 -0
- package/dist/src/formats/dot/drawing.js.map +1 -0
- package/dist/src/formats/dot/exporter.d.ts.map +1 -1
- package/dist/src/formats/dot/exporter.js +34 -2
- package/dist/src/formats/dot/exporter.js.map +1 -1
- package/dist/src/formats/dot/importer.d.ts +6 -1
- package/dist/src/formats/dot/importer.d.ts.map +1 -1
- package/dist/src/formats/dot/importer.js +170 -33
- package/dist/src/formats/dot/importer.js.map +1 -1
- package/dist/src/formats/dot/index.d.ts +3 -1
- package/dist/src/formats/dot/index.d.ts.map +1 -1
- package/dist/src/formats/dot/index.js +2 -1
- package/dist/src/formats/dot/index.js.map +1 -1
- package/dist/src/formats/dot/label-places.d.ts +41 -0
- package/dist/src/formats/dot/label-places.d.ts.map +1 -0
- package/dist/src/formats/dot/label-places.js +185 -0
- package/dist/src/formats/dot/label-places.js.map +1 -0
- package/dist/src/formats/dot/names.d.ts +13 -0
- package/dist/src/formats/dot/names.d.ts.map +1 -1
- package/dist/src/formats/dot/names.js +13 -0
- package/dist/src/formats/dot/names.js.map +1 -1
- package/dist/src/formats/dot/record.d.ts +50 -0
- package/dist/src/formats/dot/record.d.ts.map +1 -0
- package/dist/src/formats/dot/record.js +275 -0
- package/dist/src/formats/dot/record.js.map +1 -0
- package/dist/src/formats/dot/styles.d.ts +72 -2
- package/dist/src/formats/dot/styles.d.ts.map +1 -1
- package/dist/src/formats/dot/styles.js +1500 -119
- package/dist/src/formats/dot/styles.js.map +1 -1
- package/dist/src/formats/gexf/dialog-metrics.d.ts +15 -0
- package/dist/src/formats/gexf/dialog-metrics.d.ts.map +1 -0
- package/dist/src/formats/gexf/dialog-metrics.js +59 -0
- package/dist/src/formats/gexf/dialog-metrics.js.map +1 -0
- package/dist/src/formats/gexf/importer.d.ts +7 -0
- package/dist/src/formats/gexf/importer.d.ts.map +1 -1
- package/dist/src/formats/gexf/importer.js +41 -5
- package/dist/src/formats/gexf/importer.js.map +1 -1
- package/dist/src/formats/gexf/preview.d.ts +77 -0
- package/dist/src/formats/gexf/preview.d.ts.map +1 -0
- package/dist/src/formats/gexf/preview.js +191 -0
- package/dist/src/formats/gexf/preview.js.map +1 -0
- package/dist/src/formats/gexf/schema.d.ts.map +1 -1
- package/dist/src/formats/gexf/schema.js +2 -1
- package/dist/src/formats/gexf/schema.js.map +1 -1
- package/dist/src/formats/gexf/styles.d.ts +58 -31
- package/dist/src/formats/gexf/styles.d.ts.map +1 -1
- package/dist/src/formats/gexf/styles.js +848 -225
- package/dist/src/formats/gexf/styles.js.map +1 -1
- package/dist/src/formats/gml/importer.d.ts +5 -2
- package/dist/src/formats/gml/importer.d.ts.map +1 -1
- package/dist/src/formats/gml/importer.js +258 -71
- package/dist/src/formats/gml/importer.js.map +1 -1
- package/dist/src/formats/gml/index.d.ts +1 -1
- package/dist/src/formats/gml/index.d.ts.map +1 -1
- package/dist/src/formats/gml/index.js +1 -1
- package/dist/src/formats/gml/index.js.map +1 -1
- package/dist/src/formats/gml/positions.d.ts +7 -0
- package/dist/src/formats/gml/positions.d.ts.map +1 -1
- package/dist/src/formats/gml/positions.js +29 -7
- package/dist/src/formats/gml/positions.js.map +1 -1
- package/dist/src/formats/gml/styles.d.ts.map +1 -1
- package/dist/src/formats/gml/styles.js +754 -102
- package/dist/src/formats/gml/styles.js.map +1 -1
- package/dist/src/formats/graphml/styles-plain.d.ts.map +1 -1
- package/dist/src/formats/graphml/styles-plain.js +6 -10
- package/dist/src/formats/graphml/styles-plain.js.map +1 -1
- package/dist/src/formats/graphml/styles-yed.d.ts +21 -15
- package/dist/src/formats/graphml/styles-yed.d.ts.map +1 -1
- package/dist/src/formats/graphml/styles-yed.js +695 -164
- package/dist/src/formats/graphml/styles-yed.js.map +1 -1
- package/dist/src/formats/graphml/styles-yfiles3.d.ts +1 -1
- package/dist/src/formats/graphml/styles-yfiles3.d.ts.map +1 -1
- package/dist/src/formats/graphml/styles-yfiles3.js +431 -64
- package/dist/src/formats/graphml/styles-yfiles3.js.map +1 -1
- package/dist/src/formats/graphml/yfiles.d.ts +3 -3
- package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
- package/dist/src/formats/graphml/yfiles.js +16 -6
- package/dist/src/formats/graphml/yfiles.js.map +1 -1
- package/dist/src/formats/json/dialect.d.ts +3 -2
- package/dist/src/formats/json/dialect.d.ts.map +1 -1
- package/dist/src/formats/json/dialect.js +39 -5
- package/dist/src/formats/json/dialect.js.map +1 -1
- package/dist/src/formats/json/importer.d.ts +13 -2
- package/dist/src/formats/json/importer.d.ts.map +1 -1
- package/dist/src/formats/json/importer.js +42 -6
- package/dist/src/formats/json/importer.js.map +1 -1
- package/dist/src/formats/json/index.d.ts +1 -1
- package/dist/src/formats/json/index.d.ts.map +1 -1
- package/dist/src/formats/json/index.js +1 -1
- package/dist/src/formats/json/index.js.map +1 -1
- package/dist/src/formats/json/positions.d.ts +5 -2
- package/dist/src/formats/json/positions.d.ts.map +1 -1
- package/dist/src/formats/json/positions.js +20 -4
- package/dist/src/formats/json/positions.js.map +1 -1
- package/dist/src/formats/json/styles.d.ts +12 -1
- package/dist/src/formats/json/styles.d.ts.map +1 -1
- package/dist/src/formats/json/styles.js +1843 -136
- package/dist/src/formats/json/styles.js.map +1 -1
- package/dist/src/formats/pajek/draw.d.ts +104 -0
- package/dist/src/formats/pajek/draw.d.ts.map +1 -0
- package/dist/src/formats/pajek/draw.js +382 -0
- package/dist/src/formats/pajek/draw.js.map +1 -0
- package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
- package/dist/src/formats/pajek/exporter.js +70 -51
- package/dist/src/formats/pajek/exporter.js.map +1 -1
- package/dist/src/formats/pajek/importer.d.ts +9 -0
- package/dist/src/formats/pajek/importer.d.ts.map +1 -1
- package/dist/src/formats/pajek/importer.js +233 -102
- package/dist/src/formats/pajek/importer.js.map +1 -1
- package/dist/src/formats/pajek/index.d.ts +1 -0
- package/dist/src/formats/pajek/index.d.ts.map +1 -1
- package/dist/src/formats/pajek/index.js.map +1 -1
- package/dist/src/formats/pajek/styles.d.ts +15 -7
- package/dist/src/formats/pajek/styles.d.ts.map +1 -1
- package/dist/src/formats/pajek/styles.js +1395 -114
- package/dist/src/formats/pajek/styles.js.map +1 -1
- package/dist/src/formats/pajek/syntax.d.ts +10 -1
- package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
- package/dist/src/formats/pajek/syntax.js +26 -2
- package/dist/src/formats/pajek/syntax.js.map +1 -1
- package/dist/src/formats/xgmml/emit.d.ts +1 -0
- package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
- package/dist/src/formats/xgmml/emit.js +65 -5
- package/dist/src/formats/xgmml/emit.js.map +1 -1
- package/dist/src/formats/xgmml/styles.d.ts +23 -3
- package/dist/src/formats/xgmml/styles.d.ts.map +1 -1
- package/dist/src/formats/xgmml/styles.js +277 -60
- package/dist/src/formats/xgmml/styles.js.map +1 -1
- package/dist/src/index.d.ts +6 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/positions/convert.d.ts.map +1 -1
- package/dist/src/positions/convert.js +11 -1
- package/dist/src/positions/convert.js.map +1 -1
- package/dist/src/positions/extract.d.ts.map +1 -1
- package/dist/src/positions/extract.js +53 -1
- package/dist/src/positions/extract.js.map +1 -1
- package/dist/src/positions/index.d.ts +1 -1
- package/dist/src/positions/index.d.ts.map +1 -1
- package/dist/src/positions/types.d.ts +59 -0
- package/dist/src/positions/types.d.ts.map +1 -1
- package/dist/src/sources/builtins.d.ts +1 -1
- package/dist/src/sources/builtins.d.ts.map +1 -1
- package/dist/src/sources/builtins.js +8 -2
- package/dist/src/sources/builtins.js.map +1 -1
- package/dist/src/sources/context.d.ts.map +1 -1
- package/dist/src/sources/context.js +1 -0
- package/dist/src/sources/context.js.map +1 -1
- package/dist/src/sources/credentials.d.ts +50 -1
- package/dist/src/sources/credentials.d.ts.map +1 -1
- package/dist/src/sources/credentials.js +69 -0
- package/dist/src/sources/credentials.js.map +1 -1
- package/dist/src/sources/cypher/descriptor.d.ts.map +1 -1
- package/dist/src/sources/cypher/descriptor.js +5 -0
- package/dist/src/sources/cypher/descriptor.js.map +1 -1
- package/dist/src/sources/cypher/index.d.ts.map +1 -1
- package/dist/src/sources/cypher/index.js +125 -18
- package/dist/src/sources/cypher/index.js.map +1 -1
- package/dist/src/sources/cypher/params.d.ts +1 -1
- package/dist/src/sources/cypher/params.d.ts.map +1 -1
- package/dist/src/sources/cypher/query-builder.d.ts +17 -0
- package/dist/src/sources/cypher/query-builder.d.ts.map +1 -1
- package/dist/src/sources/cypher/query-builder.js +31 -0
- package/dist/src/sources/cypher/query-builder.js.map +1 -1
- package/dist/src/sources/ids.d.ts +5 -0
- package/dist/src/sources/ids.d.ts.map +1 -1
- package/dist/src/sources/ids.js +5 -0
- package/dist/src/sources/ids.js.map +1 -1
- package/dist/src/sources/params.d.ts +3 -0
- package/dist/src/sources/params.d.ts.map +1 -1
- package/dist/src/sources/rest/descriptor.d.ts.map +1 -1
- package/dist/src/sources/rest/descriptor.js +9 -0
- package/dist/src/sources/rest/descriptor.js.map +1 -1
- package/dist/src/sources/rest/openalex.d.ts +4 -2
- package/dist/src/sources/rest/openalex.d.ts.map +1 -1
- package/dist/src/sources/rest/openalex.js +4 -2
- package/dist/src/sources/rest/openalex.js.map +1 -1
- package/dist/src/sources/rest/source.d.ts.map +1 -1
- package/dist/src/sources/rest/source.js +38 -0
- package/dist/src/sources/rest/source.js.map +1 -1
- package/dist/src/sources/run.d.ts +2 -0
- package/dist/src/sources/run.d.ts.map +1 -1
- package/dist/src/sources/run.js +30 -3
- package/dist/src/sources/run.js.map +1 -1
- package/dist/src/sources/sigv4.d.ts +5 -3
- package/dist/src/sources/sigv4.d.ts.map +1 -1
- package/dist/src/sources/sigv4.js +6 -4
- package/dist/src/sources/sigv4.js.map +1 -1
- package/dist/src/sources/sparql/descriptor.d.ts +10 -0
- package/dist/src/sources/sparql/descriptor.d.ts.map +1 -0
- package/dist/src/sources/sparql/descriptor.js +64 -0
- package/dist/src/sources/sparql/descriptor.js.map +1 -0
- package/dist/src/sources/sparql/index.d.ts +28 -0
- package/dist/src/sources/sparql/index.d.ts.map +1 -0
- package/dist/src/sources/sparql/index.js +327 -0
- package/dist/src/sources/sparql/index.js.map +1 -0
- package/dist/src/sources/sparql/ntriples.d.ts +69 -0
- package/dist/src/sources/sparql/ntriples.d.ts.map +1 -0
- package/dist/src/sources/sparql/ntriples.js +180 -0
- package/dist/src/sources/sparql/ntriples.js.map +1 -0
- package/dist/src/sources/sparql/params.d.ts +27 -0
- package/dist/src/sources/sparql/params.d.ts.map +1 -0
- package/dist/src/sources/sparql/params.js +5 -0
- package/dist/src/sources/sparql/params.js.map +1 -0
- package/dist/src/sources/sparql/query.d.ts +73 -0
- package/dist/src/sources/sparql/query.d.ts.map +1 -0
- package/dist/src/sources/sparql/query.js +164 -0
- package/dist/src/sources/sparql/query.js.map +1 -0
- package/dist/src/sources/types.d.ts +60 -0
- package/dist/src/sources/types.d.ts.map +1 -1
- package/dist/src/styles/annotations.d.ts +61 -5
- package/dist/src/styles/annotations.d.ts.map +1 -1
- package/dist/src/styles/annotations.js +130 -22
- package/dist/src/styles/annotations.js.map +1 -1
- package/dist/src/styles/canon/bends.d.ts +46 -0
- package/dist/src/styles/canon/bends.d.ts.map +1 -1
- package/dist/src/styles/canon/bends.js +123 -0
- package/dist/src/styles/canon/bends.js.map +1 -1
- package/dist/src/styles/canon/color-tables.d.ts +6 -1
- package/dist/src/styles/canon/color-tables.d.ts.map +1 -1
- package/dist/src/styles/canon/color-tables.js +10 -4
- package/dist/src/styles/canon/color-tables.js.map +1 -1
- package/dist/src/styles/canon/color.d.ts +3 -1
- package/dist/src/styles/canon/color.d.ts.map +1 -1
- package/dist/src/styles/canon/color.js +103 -3
- package/dist/src/styles/canon/color.js.map +1 -1
- package/dist/src/styles/canon/enums.d.ts +2 -2
- package/dist/src/styles/canon/enums.d.ts.map +1 -1
- package/dist/src/styles/canon/enums.js +89 -7
- package/dist/src/styles/canon/enums.js.map +1 -1
- package/dist/src/styles/canon/graphviz.d.ts +12 -3
- package/dist/src/styles/canon/graphviz.d.ts.map +1 -1
- package/dist/src/styles/canon/graphviz.js +57 -9
- package/dist/src/styles/canon/graphviz.js.map +1 -1
- package/dist/src/styles/canon/number.d.ts +8 -0
- package/dist/src/styles/canon/number.d.ts.map +1 -1
- package/dist/src/styles/canon/number.js +18 -0
- package/dist/src/styles/canon/number.js.map +1 -1
- package/dist/src/styles/canon/text.d.ts +29 -2
- package/dist/src/styles/canon/text.d.ts.map +1 -1
- package/dist/src/styles/canon/text.js +156 -16
- package/dist/src/styles/canon/text.js.map +1 -1
- package/dist/src/styles/codes.d.ts +2 -0
- package/dist/src/styles/codes.d.ts.map +1 -1
- package/dist/src/styles/codes.js +2 -0
- package/dist/src/styles/codes.js.map +1 -1
- package/dist/src/styles/cyjs/cascade.d.ts.map +1 -1
- package/dist/src/styles/cyjs/cascade.js +1139 -79
- package/dist/src/styles/cyjs/cascade.js.map +1 -1
- package/dist/src/styles/cyjs/defaults-table.d.ts.map +1 -1
- package/dist/src/styles/cyjs/defaults-table.js +4 -0
- package/dist/src/styles/cyjs/defaults-table.js.map +1 -1
- package/dist/src/styles/cyjs/emit.d.ts.map +1 -1
- package/dist/src/styles/cyjs/emit.js +232 -10
- package/dist/src/styles/cyjs/emit.js.map +1 -1
- package/dist/src/styles/cyjs/face.d.ts +20 -0
- package/dist/src/styles/cyjs/face.d.ts.map +1 -0
- package/dist/src/styles/cyjs/face.js +332 -0
- package/dist/src/styles/cyjs/face.js.map +1 -0
- package/dist/src/styles/cyjs/mappers.d.ts +44 -1
- package/dist/src/styles/cyjs/mappers.d.ts.map +1 -1
- package/dist/src/styles/cyjs/mappers.js +475 -26
- package/dist/src/styles/cyjs/mappers.js.map +1 -1
- package/dist/src/styles/cyjs/routes.d.ts +53 -0
- package/dist/src/styles/cyjs/routes.d.ts.map +1 -0
- package/dist/src/styles/cyjs/routes.js +360 -0
- package/dist/src/styles/cyjs/routes.js.map +1 -0
- package/dist/src/styles/cytoscape/charts.d.ts +23 -0
- package/dist/src/styles/cytoscape/charts.d.ts.map +1 -0
- package/dist/src/styles/cytoscape/charts.js +560 -0
- package/dist/src/styles/cytoscape/charts.js.map +1 -0
- package/dist/src/styles/cytoscape/emit.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/emit.js +156 -48
- package/dist/src/styles/cytoscape/emit.js.map +1 -1
- package/dist/src/styles/cytoscape/lexicon.d.ts +91 -3
- package/dist/src/styles/cytoscape/lexicon.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/lexicon.js +387 -77
- package/dist/src/styles/cytoscape/lexicon.js.map +1 -1
- package/dist/src/styles/cytoscape/mappings.d.ts +30 -0
- package/dist/src/styles/cytoscape/mappings.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/mappings.js +92 -0
- package/dist/src/styles/cytoscape/mappings.js.map +1 -1
- package/dist/src/styles/cytoscape/resolve.d.ts +42 -2
- package/dist/src/styles/cytoscape/resolve.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/resolve.js +623 -17
- package/dist/src/styles/cytoscape/resolve.js.map +1 -1
- package/dist/src/styles/defaults.d.ts +46 -26
- package/dist/src/styles/defaults.d.ts.map +1 -1
- package/dist/src/styles/defaults.js +308 -71
- package/dist/src/styles/defaults.js.map +1 -1
- package/dist/src/styles/index.d.ts +4 -3
- package/dist/src/styles/index.d.ts.map +1 -1
- package/dist/src/styles/index.js +3 -2
- package/dist/src/styles/index.js.map +1 -1
- package/dist/src/styles/internal.d.ts +1 -0
- package/dist/src/styles/internal.d.ts.map +1 -1
- package/dist/src/styles/internal.js +1 -0
- package/dist/src/styles/internal.js.map +1 -1
- package/dist/src/styles/io/generic.d.ts.map +1 -1
- package/dist/src/styles/io/generic.js +56 -16
- package/dist/src/styles/io/generic.js.map +1 -1
- package/dist/src/styles/io/round-trip.d.ts +56 -0
- package/dist/src/styles/io/round-trip.d.ts.map +1 -0
- package/dist/src/styles/io/round-trip.js +138 -0
- package/dist/src/styles/io/round-trip.js.map +1 -0
- package/dist/src/styles/io/writer.d.ts.map +1 -1
- package/dist/src/styles/io/writer.js +6 -1
- package/dist/src/styles/io/writer.js.map +1 -1
- package/dist/src/styles/notes.d.ts.map +1 -1
- package/dist/src/styles/notes.js +1 -0
- package/dist/src/styles/notes.js.map +1 -1
- package/dist/src/styles/plan/features.d.ts +1 -1
- package/dist/src/styles/plan/features.d.ts.map +1 -1
- package/dist/src/styles/plan/features.js +22 -2
- package/dist/src/styles/plan/features.js.map +1 -1
- package/dist/src/styles/plan/index.d.ts +1 -1
- package/dist/src/styles/plan/index.d.ts.map +1 -1
- package/dist/src/styles/plan/index.js +1 -1
- package/dist/src/styles/plan/index.js.map +1 -1
- package/dist/src/styles/plan/plan.d.ts.map +1 -1
- package/dist/src/styles/plan/plan.js +61 -4
- package/dist/src/styles/plan/plan.js.map +1 -1
- package/dist/src/styles/plan/resolve.d.ts +11 -0
- package/dist/src/styles/plan/resolve.d.ts.map +1 -1
- package/dist/src/styles/plan/resolve.js +40 -4
- package/dist/src/styles/plan/resolve.js.map +1 -1
- package/dist/src/styles/slots.d.ts +14 -0
- package/dist/src/styles/slots.d.ts.map +1 -0
- package/dist/src/styles/slots.js +20 -0
- package/dist/src/styles/slots.js.map +1 -0
- package/dist/src/styles/types.d.ts +687 -6
- package/dist/src/styles/types.d.ts.map +1 -1
- package/dist/src/styles/vocabulary.d.ts +3 -2
- package/dist/src/styles/vocabulary.d.ts.map +1 -1
- package/dist/src/styles/vocabulary.js +224 -0
- package/dist/src/styles/vocabulary.js.map +1 -1
- package/dist/styles.js +30 -239
- package/dist/styles.js.map +1 -1
- package/dist/xgmml.js +3 -3
- package/package.json +27 -7
- package/src/formats/cx/importer.ts +6 -1
- package/src/formats/cx/styles.ts +143 -9
- package/src/formats/cx2/importer.ts +1 -0
- package/src/formats/cx2/styles.ts +3 -1
- package/src/formats/cys/importer.ts +1 -0
- package/src/formats/cys/styles.ts +27 -5
- package/src/formats/dot/drawing.ts +799 -0
- package/src/formats/dot/exporter.ts +37 -1
- package/src/formats/dot/importer.ts +192 -36
- package/src/formats/dot/index.ts +3 -1
- package/src/formats/dot/label-places.ts +241 -0
- package/src/formats/dot/names.ts +15 -0
- package/src/formats/dot/record.ts +336 -0
- package/src/formats/dot/styles.ts +1702 -149
- package/src/formats/gexf/dialog-metrics.ts +61 -0
- package/src/formats/gexf/importer.ts +50 -5
- package/src/formats/gexf/preview.ts +217 -0
- package/src/formats/gexf/schema.ts +2 -1
- package/src/formats/gexf/styles.ts +1099 -245
- package/src/formats/gml/importer.ts +291 -76
- package/src/formats/gml/index.ts +1 -1
- package/src/formats/gml/positions.ts +29 -7
- package/src/formats/gml/styles.ts +852 -110
- package/src/formats/graphml/styles-plain.ts +6 -15
- package/src/formats/graphml/styles-yed.ts +765 -176
- package/src/formats/graphml/styles-yfiles3.ts +487 -63
- package/src/formats/graphml/yfiles.ts +19 -6
- package/src/formats/json/dialect.ts +41 -5
- package/src/formats/json/importer.ts +59 -7
- package/src/formats/json/index.ts +1 -0
- package/src/formats/json/positions.ts +22 -5
- package/src/formats/json/styles.ts +2123 -171
- package/src/formats/pajek/draw.ts +469 -0
- package/src/formats/pajek/exporter.ts +81 -49
- package/src/formats/pajek/importer.ts +278 -103
- package/src/formats/pajek/index.ts +1 -0
- package/src/formats/pajek/styles.ts +1506 -133
- package/src/formats/pajek/syntax.ts +27 -2
- package/src/formats/xgmml/emit.ts +73 -5
- package/src/formats/xgmml/styles.ts +330 -71
- package/src/index.ts +12 -1
- package/src/positions/convert.ts +12 -1
- package/src/positions/extract.ts +55 -1
- package/src/positions/index.ts +1 -0
- package/src/positions/types.ts +60 -0
- package/src/sources/builtins.ts +8 -1
- package/src/sources/context.ts +1 -0
- package/src/sources/credentials.ts +90 -1
- package/src/sources/cypher/descriptor.ts +7 -1
- package/src/sources/cypher/index.ts +149 -18
- package/src/sources/cypher/params.ts +1 -1
- package/src/sources/cypher/query-builder.ts +33 -0
- package/src/sources/ids.ts +6 -0
- package/src/sources/params.ts +3 -0
- package/src/sources/rest/descriptor.ts +9 -0
- package/src/sources/rest/openalex.ts +4 -2
- package/src/sources/rest/source.ts +41 -0
- package/src/sources/run.ts +35 -3
- package/src/sources/sigv4.ts +6 -4
- package/src/sources/sparql/descriptor.ts +67 -0
- package/src/sources/sparql/index.ts +371 -0
- package/src/sources/sparql/ntriples.ts +219 -0
- package/src/sources/sparql/params.ts +28 -0
- package/src/sources/sparql/query.ts +216 -0
- package/src/sources/types.ts +68 -0
- package/src/styles/annotations.ts +201 -27
- package/src/styles/canon/bends.ts +137 -0
- package/src/styles/canon/color-tables.ts +10 -4
- package/src/styles/canon/color.ts +105 -3
- package/src/styles/canon/enums.ts +107 -8
- package/src/styles/canon/graphviz.ts +71 -10
- package/src/styles/canon/number.ts +19 -0
- package/src/styles/canon/text.ts +187 -16
- package/src/styles/codes.ts +2 -0
- package/src/styles/cyjs/cascade.ts +1303 -84
- package/src/styles/cyjs/defaults-table.ts +4 -0
- package/src/styles/cyjs/emit.ts +268 -14
- package/src/styles/cyjs/face.ts +372 -0
- package/src/styles/cyjs/mappers.ts +506 -27
- package/src/styles/cyjs/routes.ts +432 -0
- package/src/styles/cytoscape/charts.ts +684 -0
- package/src/styles/cytoscape/emit.ts +170 -48
- package/src/styles/cytoscape/lexicon.ts +431 -78
- package/src/styles/cytoscape/mappings.ts +108 -0
- package/src/styles/cytoscape/resolve.ts +741 -17
- package/src/styles/defaults.ts +417 -108
- package/src/styles/index.ts +5 -0
- package/src/styles/internal.ts +1 -0
- package/src/styles/io/generic.ts +79 -23
- package/src/styles/io/round-trip.ts +202 -0
- package/src/styles/io/writer.ts +6 -1
- package/src/styles/notes.ts +1 -0
- package/src/styles/plan/features.ts +23 -2
- package/src/styles/plan/index.ts +1 -1
- package/src/styles/plan/plan.ts +69 -5
- package/src/styles/plan/resolve.ts +47 -4
- package/src/styles/slots.ts +25 -0
- package/src/styles/types.ts +698 -5
- package/src/styles/vocabulary.ts +232 -2
- package/dist/chunks/block-Cu22ewuS.js.map +0 -1
- package/dist/chunks/choose-Cdx6Enl2.js +0 -57
- package/dist/chunks/choose-Cdx6Enl2.js.map +0 -1
- package/dist/chunks/codes-CV_Bhcyi.js.map +0 -1
- package/dist/chunks/convert-BcQ8_jMo.js.map +0 -1
- package/dist/chunks/credentials-BiQsnMTb.js.map +0 -1
- package/dist/chunks/descriptor-BJ-W0Jd-.js.map +0 -1
- package/dist/chunks/emit-CD8xnY8s.js.map +0 -1
- package/dist/chunks/export-CZ7VRm4I.js.map +0 -1
- package/dist/chunks/exporter-bxxjOrDZ.js.map +0 -1
- package/dist/chunks/format-BMS-1Nxb.js +0 -64
- package/dist/chunks/format-BMS-1Nxb.js.map +0 -1
- package/dist/chunks/generic-CP6YD34u.js.map +0 -1
- package/dist/chunks/importer-B87_fmVx.js.map +0 -1
- package/dist/chunks/importer-CB_zV5_L.js.map +0 -1
- package/dist/chunks/importer-CVT-JyDE.js.map +0 -1
- package/dist/chunks/importer-Cyy6UseH.js.map +0 -1
- package/dist/chunks/importer-DPZDN40-.js.map +0 -1
- package/dist/chunks/importer-e3huMZbm.js.map +0 -1
- package/dist/chunks/lexicon-u2SI5xcx.js.map +0 -1
- package/dist/chunks/sigv4-LkAzsLAu.js.map +0 -1
- package/dist/chunks/styles-CaABMoO1.js.map +0 -1
- package/dist/chunks/styles-P_gmFAOi.js +0 -770
- package/dist/chunks/styles-P_gmFAOi.js.map +0 -1
- package/dist/chunks/styles-yed-Cs1nmrjn.js.map +0 -1
- package/dist/chunks/writer-DvHTl36J.js +0 -449
- package/dist/chunks/writer-DvHTl36J.js.map +0 -1
package/dist/graph-io.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-io.js","sources":["../src/common/line-format.ts","../src/common/compare.ts","../src/common/cell-budget.ts","../src/sources/builtins.ts","../src/sources/run.ts","../src/sources/registry.ts","../src/registry.ts","../src/sources/testing.ts"],"sourcesContent":["/**\n * defineLineFormat(): an importer for a text format with one node or one edge per line, built from\n * one function that reads a line. Everything else an importer must do (options, decoding, the\n * report and its counts, ids, direction, weights, attribute types, cancelling) is done here.\n */\n\nimport { GraphFormatError, type GraphSink, INVALID_INDEX } from \"@graphty/graph-format\";\n\nimport { type CommonImportOptions, type GraphImporter, type ImportInput, type ImportReport } from \"../types.js\";\nimport { BAD_LINE_CODE } from \"./codes.js\";\nimport { DirectionResolver } from \"./direction.js\";\nimport { IdCoercer } from \"./ids.js\";\nimport { LineReader, throwIfAborted } from \"./input.js\";\nimport { reportSinkOptions, reportUnusedOptions, resolveImportOptions } from \"./options.js\";\nimport { ImportReportBuilder, isAbortError, messageOf } from \"./report.js\";\nimport { TextCellWriter } from \"./text.js\";\nimport { parseWeightText } from \"./weights.js\";\n\n/**\n * Attribute values for a node or an edge added by defineLineFormat()'s `parseLine`.\n * @category Writing a format\n */\nexport type LineAttributes = Readonly<Record<string, string | number | boolean | null | undefined>>;\n\n/**\n * What `parseLine` adds a line's node or edge with.\n * @category Writing a format\n */\nexport interface LineGraph {\n /**\n * Add a node, or give a node that already exists more attributes. A `label` attribute is the\n * node's label, which `snapshot.nodes.byRole(\"label\")` finds; any other attribute's type (text,\n * integer, number, boolean) is worked out from its values, as for a CSV column.\n * @param id - the node id as written in the file\n * @param attributes - attribute values, such as `{ label: \"Alice\" }`\n */\n node(id: string, attributes?: LineAttributes): void;\n /**\n * Add an edge. A node it names that does not exist yet is added. The attribute that `weightFrom`\n * names (`weight` unless the caller passes another name) becomes the edge weight.\n * @param source - the source node id as written in the file\n * @param target - the target node id as written in the file\n * @param attributes - attribute values, such as `{ weight: \"2.5\" }`\n */\n edge(source: string, target: string, attributes?: LineAttributes): void;\n}\n\n/**\n * A text format with one node or one edge per line, for defineLineFormat().\n * @category Writing a format\n */\nexport interface LineFormat {\n /** The format name, which callers pass as `format`. */\n readonly format: string;\n /** The file extensions, with the dot (`[\".tgf\"]`); format detection matches them. */\n readonly extensions: readonly string[];\n /** MIME types the format is served as; none when left out. */\n readonly mimeTypes?: readonly string[] | undefined;\n /** Whether a file is directed when the caller passes no `defaultDirected`; false when left out. */\n readonly directed?: boolean | undefined;\n /** Lines that start with this text are skipped; `\"#\"` when left out, null to skip none. Blank lines are always skipped. */\n readonly comment?: string | null | undefined;\n /**\n * How sure you are that the first bytes of a file are this format, from 0 to 1. A file is\n * recognized by its content only when this returns 0.5 or more; without it, detection goes by\n * the file extension.\n */\n readonly sniff?: ((head: Uint8Array) => number) | undefined;\n /**\n * Read one line. `fields` is the line split on whitespace. Call `graph.node()` or `graph.edge()`\n * for what the line holds, and throw an Error to skip a line you cannot read: its message is\n * recorded as an `E_BAD_LINE` error with the line number.\n */\n readonly parseLine: (fields: readonly string[], graph: LineGraph, line: string) => void;\n}\n\n/** The common options a line format reads; a caller's other ones are reported as W_OPTION_IGNORED. */\nconst USED = new Set<keyof CommonImportOptions>([\"ids\", \"defaultDirected\", \"weightFrom\", \"addMissingNodes\"]);\n\n/**\n * Make an importer for a text format with one node or one edge per line. You write `parseLine`,\n * which reads one line; the importer handles every input graph-io takes, the options every importer\n * takes, the import report and its counts, cancelling and progress. Register the result with\n * `registry.registerImporter()`.\n * @example\n * ```ts\n * // \"a b\" is an edge, \"a\" alone is a node\n * const edgeList = defineLineFormat({\n * format: \"edges\",\n * extensions: [\".edges\"],\n * parseLine(fields, graph) {\n * if (fields.length === 1) {\n * graph.node(fields[0]);\n * } else if (fields.length === 2) {\n * graph.edge(fields[0], fields[1]);\n * } else {\n * throw new Error(\"expected one or two node ids\");\n * }\n * },\n * });\n * registry.registerImporter(edgeList);\n * ```\n * @param definition - the format: its name, extensions and `parseLine`\n * @returns the importer\n * @category Writing a format\n */\nexport function defineLineFormat(definition: LineFormat): GraphImporter {\n const { format, extensions, mimeTypes = [], directed = false, comment = \"#\", sniff, parseLine } = definition;\n const importer: GraphImporter = {\n format,\n extensions,\n mimeTypes,\n options: [],\n import: async (input: ImportInput, sink: GraphSink, options?: CommonImportOptions): Promise<ImportReport> => {\n const opts = resolveImportOptions(options, {\n ids: \"canonical\",\n defaultDirected: directed,\n weightFrom: \"weight\",\n });\n const report = new ImportReportBuilder(format, opts.errorLimit);\n reportSinkOptions(sink, options, report);\n reportUnusedOptions(options, report, USED);\n const ids = new IdCoercer(opts.ids);\n const edges = new DirectionResolver(sink, report, opts.onMixedDirection);\n const kind = opts.defaultDirected ? \"directed\" : \"undirected\";\n edges.setHeader(opts.defaultDirected);\n const attributes = new AttributeWriter(sink, report, opts.weightFrom);\n const write = (domain: \"node\" | \"edge\", row: number, values: LineAttributes | undefined): void => {\n attributes.write(domain, row, values);\n };\n const addNode = (id: string): number => {\n const nodeId = ids.text(id);\n if (sink.indexOf(nodeId) === INVALID_INDEX) {\n report.counts.nodes++;\n }\n return sink.addNode(nodeId);\n };\n let line = 0;\n const graph: LineGraph = {\n node: (id, attributes) => {\n write(\"node\", addNode(id), attributes);\n },\n edge: (source, target, attributes) => {\n const raw = opts.weightFrom === null ? undefined : attributes?.[opts.weightFrom];\n const weight = raw === null || raw === undefined ? undefined : parseWeightText(String(raw), report);\n const [s, t] = [ids.text(source), ids.text(target)];\n const added = new Set([s, t].filter((id) => sink.indexOf(id) === INVALID_INDEX)).size;\n const edge = edges.addEdge(s, t, kind, weight, { line });\n report.counts.nodes += added;\n report.counts.edges++;\n write(\"edge\", edge, attributes);\n },\n };\n const lines = new LineReader(input, report, opts);\n for await (const text of lines) {\n ({ line } = lines);\n if (line % 64 === 0) {\n throwIfAborted(opts.signal);\n }\n const trimmed = text.trim();\n if (trimmed === \"\" || (comment !== null && trimmed.startsWith(comment))) {\n continue;\n }\n try {\n parseLine(trimmed.split(/\\s+/), graph, text);\n } catch (err) {\n recordLineError(report, err, line);\n }\n }\n throwIfAborted(opts.signal);\n return report.finish();\n },\n };\n return Object.freeze(sniff === undefined ? importer : { ...importer, sniff });\n}\n\n/**\n * Record what a line's parser threw: a GraphFormatError with its own code, any other error as\n * BAD_LINE_CODE. A cancellation is rethrown.\n * @param report - the report\n * @param err - what the parser threw\n * @param line - the line number\n */\nfunction recordLineError(report: ImportReportBuilder, err: unknown, line: number): void {\n if (isAbortError(err)) {\n throw err;\n }\n if (err instanceof GraphFormatError) {\n report.recordError(err, { line });\n } else {\n report.error(\"parse-error\", BAD_LINE_CODE, err instanceof Error ? err.message : messageOf(err), { line });\n }\n}\n\n/** Writes the attributes a line format's parser gives a node or an edge into columns. */\nclass AttributeWriter {\n private readonly writers = { node: new Map<string, TextCellWriter>(), edge: new Map<string, TextCellWriter>() };\n\n /**\n * Create a writer.\n * @param sink - the sink\n * @param report - the report\n * @param weightFrom - the edge attribute read as the weight (not written as a column), or null\n */\n constructor(\n private readonly sink: GraphSink,\n private readonly report: ImportReportBuilder,\n private readonly weightFrom: string | null,\n ) {}\n\n /**\n * Write one element's attributes; null and undefined values are left unset.\n * @param domain - node or edge\n * @param row - the element's index\n * @param attributes - the attributes, or undefined\n */\n write(domain: \"node\" | \"edge\", row: number, attributes: LineAttributes | undefined): void {\n for (const [name, value] of Object.entries(attributes ?? {})) {\n if (value === null || value === undefined || (domain === \"edge\" && name === this.weightFrom)) {\n continue;\n }\n if (name === \"label\") {\n this.writeLabel(domain, row, String(value));\n continue;\n }\n let writer = this.writers[domain].get(name);\n if (writer === undefined) {\n writer = new TextCellWriter(name, domain, this.sink, this.report);\n this.writers[domain].set(name, writer);\n }\n writer.write(row, String(value));\n }\n }\n\n /**\n * Write a label: text, whatever it looks like, in the column that byRole(\"label\") finds.\n * @param domain - node or edge\n * @param row - the element's index\n * @param text - the label\n */\n private writeLabel(domain: \"node\" | \"edge\", row: number, text: string): void {\n const decl = { name: \"label\", dtype: \"string\", role: \"label\" } as const;\n if (domain === \"node\") {\n this.sink.setNodeValue(this.sink.declareNodeColumn(decl), row, text);\n } else {\n this.sink.setEdgeValue(this.sink.declareEdgeColumn(decl), row, text);\n }\n }\n}\n","/**\n * Compare two snapshots node by node, edge by edge and value by value, for testing a format plugin:\n * read a file, save it, read the saved file back, and compare. Every difference should be one that\n * the save's checkExport() notes announced.\n */\n\nimport { type Column, type GraphSnapshot } from \"@graphty/graph-format\";\n\n/**\n * One difference between two snapshots.\n * @category Plugin helpers\n */\nexport interface SnapshotDiff {\n /** Where: \"directed\", \"ids[3]\", \"nodes.label[4]\", \"edges.weight[0]\", \"extensions.temporal:node:price.rowCount\"... */\n readonly path: string;\n /** The value in the expected snapshot. */\n readonly expected: unknown;\n /** The value in the actual snapshot. */\n readonly actual: unknown;\n /** A one-line description. */\n readonly message: string;\n}\n\n/**\n * What compareSnapshots() compares.\n * @category Plugin helpers\n */\nexport interface CompareOptions {\n /** Column names to skip in every table (format-owned helpers an exporter adds, for instance). */\n readonly ignoreColumns?: readonly string[] | undefined;\n /** Column roles to skip in every table. */\n readonly ignoreRoles?: readonly string[] | undefined;\n /** Whether the actual snapshot may hold columns the expected one lacks (default true). */\n readonly allowExtraColumns?: boolean | undefined;\n /** Whether dtypes must match (default true); false compares values only. */\n readonly dtypes?: boolean | undefined;\n /** Whether roles must match (default true). */\n readonly roles?: boolean | undefined;\n /** Whether origin.type must match (default false). */\n readonly originType?: boolean | undefined;\n /** Absolute tolerance for numeric cell and weight comparisons (default 0: Object.is). */\n readonly tolerance?: number | undefined;\n /** Whether the explicit / defaulted status of weights must match (default true). */\n readonly weightExplicitness?: boolean | undefined;\n /** Whether extension tables are compared (default true). */\n readonly extensions?: boolean | undefined;\n /** Stop after this many differences (default 50). */\n readonly limit?: number | undefined;\n}\n\n/**\n * Compare two snapshots: the direction, the node ids, the edges, the weights and every attribute\n * value. Use it to test a format plugin: read a file, save it in your format, read the saved file\n * back, and compare the two graphs. Each difference has a `path` (\"ids[3]\", \"nodes.label[4]\",\n * \"edges.weight[0]\") and a one-line `message`; every one should match a note that `checkExport()`\n * returned for the save.\n * @example\n * ```ts\n * const notes = checkExport(original, \"pairs\");\n * const readBack = (await importGraph(await exportGraphToString(original, \"pairs\"), { format: \"pairs\" })).snapshot;\n * console.log(describeDiffs(compareSnapshots(original, readBack)));\n * ```\n * @param expected - the graph you saved\n * @param actual - the graph read back from the saved file\n * @param options - what to compare\n * @returns the differences, empty when the graphs are the same\n * @category Plugin helpers\n */\nexport function compareSnapshots(\n expected: GraphSnapshot,\n actual: GraphSnapshot,\n options: CompareOptions = {},\n): SnapshotDiff[] {\n const diffs: SnapshotDiff[] = [];\n const limit = options.limit ?? 50;\n const tolerance = options.tolerance ?? 0;\n const ctx: CompareContext = {\n options,\n diff: (path, e, a, message) => {\n diffs.push({\n path,\n expected: e,\n actual: a,\n message: message ?? `${path}: expected ${show(e)}, got ${show(a)}`,\n });\n if (diffs.length >= limit) {\n throw new LimitReached();\n }\n },\n same: (e, a) => valuesEqual(e, a, tolerance),\n };\n try {\n compareGraphs(expected, actual, ctx);\n } catch (err) {\n if (!(err instanceof LimitReached)) {\n throw err;\n }\n }\n return diffs;\n}\n\n/** Thrown by the recorder once the limit of differences is reached, to end the walk. */\nclass LimitReached extends Error {}\n\n/** What every comparison step shares: the options, the recorder and the value comparator. */\ninterface CompareContext {\n readonly options: CompareOptions;\n /** Records a difference (with a default message); throws LimitReached at the limit. */\n readonly diff: (path: string, e: unknown, a: unknown, message?: string) => void;\n /** Value equality under the tolerance. */\n readonly same: (e: unknown, a: unknown) => boolean;\n}\n\n/** A table shape both AttributeTable and extension tables satisfy. */\ninterface TableLike extends Iterable<Column> {\n readonly rowCount: number;\n names(): readonly string[];\n get(name: string): Column | null;\n}\n\n/**\n * Compare two snapshots step by step: the counts, the ids, the topology, the weights, the tables.\n * @param expected - the reference\n * @param actual - the snapshot under test\n * @param ctx - the comparison context\n */\nfunction compareGraphs(expected: GraphSnapshot, actual: GraphSnapshot, ctx: CompareContext): void {\n const { diff } = ctx;\n if (expected.directed !== actual.directed) {\n diff(\"directed\", expected.directed, actual.directed);\n }\n if (expected.nodeCount !== actual.nodeCount) {\n diff(\"nodeCount\", expected.nodeCount, actual.nodeCount);\n }\n if (expected.edgeCount !== actual.edgeCount) {\n diff(\"edgeCount\", expected.edgeCount, actual.edgeCount);\n }\n compareIds(expected, actual, diff);\n if (expected.nodeCount !== actual.nodeCount || expected.edgeCount !== actual.edgeCount) {\n return;\n }\n compareTopology(expected, actual, diff);\n compareWeights(expected, actual, ctx);\n compareTables(\"nodes\", expected.nodes, actual.nodes, ctx);\n compareTables(\"edges\", expected.edges, actual.edges, ctx);\n compareTables(\"graph\", expected.graph, actual.graph, ctx);\n if (ctx.options.extensions !== false) {\n compareExtensions(expected, actual, ctx);\n }\n}\n\n/**\n * Compare the node ids in index order.\n * @param expected - the reference\n * @param actual - the snapshot under test\n * @param diff - the recorder\n */\nfunction compareIds(expected: GraphSnapshot, actual: GraphSnapshot, diff: CompareContext[\"diff\"]): void {\n const expectedIds = expected.ids.toArray();\n const actualIds = actual.ids.toArray();\n const n = Math.min(expectedIds.length, actualIds.length);\n for (let i = 0; i < n; i++) {\n if (!Object.is(expectedIds[i], actualIds[i])) {\n diff(`ids[${i}]`, expectedIds[i], actualIds[i]);\n }\n }\n}\n\n/**\n * Compare the topology: the CSR arrays (identical when node order and edge order survived), then the\n * orientation of every logical edge.\n * @param expected - the reference\n * @param actual - the snapshot under test, with as many nodes and edges\n * @param diff - the recorder\n */\nfunction compareTopology(expected: GraphSnapshot, actual: GraphSnapshot, diff: CompareContext[\"diff\"]): void {\n if (!typedEqual(expected.rowPtr, actual.rowPtr)) {\n diff(\"rowPtr\", expected.rowPtr, actual.rowPtr, \"rowPtr differs\");\n }\n if (!typedEqual(expected.colIdx, actual.colIdx)) {\n diff(\"colIdx\", expected.colIdx, actual.colIdx, \"colIdx differs\");\n }\n const el = expected.edgeList();\n const al = actual.edgeList();\n for (let e = 0; e < expected.edgeCount; e++) {\n if (el.src[e] !== al.src[e] || el.dst[e] !== al.dst[e]) {\n diff(`edge[${e}]`, `${el.src[e]}->${el.dst[e]}`, `${al.src[e]}->${al.dst[e]}`);\n }\n }\n}\n\n/**\n * Compare the weights of two snapshots: the exact weight column when both have one, the 32-bit\n * weights otherwise.\n * @param expected - the reference\n * @param actual - the snapshot under test\n * @param ctx - the comparison context\n */\nfunction compareWeights(expected: GraphSnapshot, actual: GraphSnapshot, ctx: CompareContext): void {\n if (expected.flags.weighted !== actual.flags.weighted) {\n ctx.diff(\"flags.weighted\", expected.flags.weighted, actual.flags.weighted);\n return;\n }\n if (!expected.flags.weighted) {\n return;\n }\n const eShadow = expected.edges.byRole(\"weight\");\n const aShadow = actual.edges.byRole(\"weight\");\n if (eShadow !== null && aShadow !== null) {\n compareExactWeights(expected.edgeCount, eShadow, aShadow, ctx);\n return;\n }\n if (ctx.options.weightExplicitness !== false && (eShadow === null) !== (aShadow === null)) {\n ctx.diff(\n \"weightColumn\",\n eShadow !== null,\n aShadow !== null,\n \"one snapshot has a role-weight column, the other does not\",\n );\n }\n const ew = expected.edgeList().weights;\n const aw = actual.edgeList().weights;\n for (let e = 0; e < expected.edgeCount; e++) {\n const ev = ew === null ? 1 : ew[e];\n const av = aw === null ? 1 : aw[e];\n if (!ctx.same(ev, av)) {\n ctx.diff(`weight[${e}]`, ev, av);\n }\n }\n}\n\n/**\n * Compare the exact weight columns of two snapshots: which edges have an explicit weight, and its value.\n * @param edgeCount - the number of edges\n * @param expected - the reference's weight column\n * @param actual - the weight column under test\n * @param ctx - the comparison context\n */\nfunction compareExactWeights(edgeCount: number, expected: Column, actual: Column, ctx: CompareContext): void {\n for (let e = 0; e < edgeCount; e++) {\n const eSet = expected.isSet(e);\n const aSet = actual.isSet(e);\n if (ctx.options.weightExplicitness !== false && eSet !== aSet) {\n ctx.diff(`weightExplicit[${e}]`, eSet, aSet);\n } else if (eSet && aSet && !ctx.same(expected.value(e), actual.value(e))) {\n ctx.diff(`weight[${e}]`, expected.value(e), actual.value(e));\n }\n }\n}\n\n/**\n * Compare the extension tables: which exist, their row counts and their columns.\n * @param expected - the reference\n * @param actual - the snapshot under test\n * @param ctx - the comparison context\n */\nfunction compareExtensions(expected: GraphSnapshot, actual: GraphSnapshot, ctx: CompareContext): void {\n for (const [name, table] of expected.extensions) {\n const other = actual.extensions.get(name);\n if (other === undefined) {\n ctx.diff(`extensions.${name}`, \"present\", \"absent\");\n } else if (table.rowCount === other.rowCount) {\n compareTables(`extensions.${name}`, table, other, ctx);\n } else {\n ctx.diff(`extensions.${name}.rowCount`, table.rowCount, other.rowCount);\n }\n }\n if (ctx.options.allowExtraColumns === false) {\n for (const name of actual.extensions.keys()) {\n if (!expected.extensions.has(name)) {\n ctx.diff(`extensions.${name}`, \"absent\", \"present\");\n }\n }\n }\n}\n\n/**\n * Compare the columns of one table.\n * @param label - the table name for paths\n * @param expected - the reference table\n * @param actual - the table under test\n * @param ctx - the comparison context\n */\nfunction compareTables(label: string, expected: TableLike, actual: TableLike, ctx: CompareContext): void {\n const ignoreNames = new Set(ctx.options.ignoreColumns ?? []);\n const ignoreRoles = new Set(ctx.options.ignoreRoles ?? []);\n // the role-weight shadow column is compared by the weights step, not as a declared column\n const skip = (column: Column): boolean => {\n const { name, role } = column.meta;\n return (\n ignoreNames.has(name) ||\n (role !== null && (ignoreRoles.has(role) || (label === \"edges\" && role === \"weight\")))\n );\n };\n for (const column of expected) {\n if (skip(column)) {\n continue;\n }\n const path = `${label}.${column.meta.name}`;\n const other = actual.get(column.meta.name);\n if (other === null) {\n ctx.diff(path, \"present\", \"absent\", `${path}: column missing after round trip`);\n } else {\n compareColumn(path, column, other, ctx);\n }\n }\n if (ctx.options.allowExtraColumns === false) {\n for (const column of actual) {\n if (!skip(column) && expected.get(column.meta.name) === null) {\n const path = `${label}.${column.meta.name}`;\n ctx.diff(path, \"absent\", \"present\", `${path}: extra column after round trip`);\n }\n }\n }\n}\n\n/**\n * Compare one column: its declaration, then every cell.\n * @param path - the column's path for messages\n * @param column - the reference column\n * @param other - the column under test\n * @param ctx - the comparison context\n */\nfunction compareColumn(path: string, column: Column, other: Column, ctx: CompareContext): void {\n compareDeclaration(path, column, other, ctx);\n if (column.length !== other.length) {\n ctx.diff(`${path}.length`, column.length, other.length);\n return;\n }\n for (let r = 0; r < column.length; r++) {\n const eSet = column.isSet(r);\n const aSet = other.isSet(r);\n if (eSet !== aSet) {\n ctx.diff(`${path}[${r}]`, eSet ? column.value(r) : undefined, aSet ? other.value(r) : undefined);\n } else if (eSet) {\n const ev = cellValue(column, r);\n const av = cellValue(other, r);\n if (!ctx.same(ev, av)) {\n ctx.diff(`${path}[${r}]`, ev, av);\n }\n }\n }\n}\n\n/**\n * Compare what two columns declare: dtype, item dtype, components, role and origin type, as the\n * options ask.\n * @param path - the column's path for messages\n * @param column - the reference column\n * @param other - the column under test\n * @param ctx - the comparison context\n */\nfunction compareDeclaration(path: string, column: Column, other: Column, ctx: CompareContext): void {\n const { options, diff } = ctx;\n const e = column.meta;\n const a = other.meta;\n if (options.dtypes !== false) {\n for (const key of [\"dtype\", \"itemDtype\", \"components\"] as const) {\n if (e[key] !== a[key]) {\n diff(`${path}.${key}`, e[key], a[key]);\n }\n }\n }\n if (options.roles !== false && e.role !== a.role) {\n diff(`${path}.role`, e.role, a.role);\n }\n const eType = e.origin?.type ?? null;\n const aType = a.origin?.type ?? null;\n if (options.originType === true && eType !== aType) {\n diff(`${path}.origin.type`, eType, aType);\n }\n}\n\n/**\n * The comparable value of a set cell: list rows through sliceOf, json rows through values, the\n * typed accessor otherwise (a components > 1 subarray becomes a plain array).\n * @param column - the column\n * @param row - the row\n * @returns the value\n */\nfunction cellValue(column: Column, row: number): unknown {\n switch (column.dtype) {\n case \"list\":\n return [...column.sliceOf(row)];\n case \"json\":\n return column.values[row];\n default: {\n const value = column.value(row);\n return ArrayBuffer.isView(value) ? Array.from(value as ArrayLike<number>) : value;\n }\n }\n}\n\n/**\n * Deep equality with a numeric tolerance (for the tests).\n * @param e - expected\n * @param a - actual\n * @param tolerance - absolute tolerance for numbers\n * @returns true when equal\n */\nexport function valuesEqual(e: unknown, a: unknown, tolerance: number): boolean {\n if (typeof e === \"number\" && typeof a === \"number\") {\n if (Object.is(e, a)) {\n return true;\n }\n return Number.isFinite(e) && Number.isFinite(a) && Math.abs(e - a) <= tolerance;\n }\n if (Array.isArray(e) || ArrayBuffer.isView(e)) {\n const ea = Array.from(e as ArrayLike<unknown>);\n if (!(Array.isArray(a) || ArrayBuffer.isView(a))) {\n return false;\n }\n const aa = Array.from(a as ArrayLike<unknown>);\n return ea.length === aa.length && ea.every((v, i) => valuesEqual(v, aa[i], tolerance));\n }\n if (typeof e === \"object\" && e !== null && typeof a === \"object\" && a !== null) {\n const eo = e as Record<string, unknown>;\n const ao = a as Record<string, unknown>;\n const keys = Object.keys(eo);\n if (keys.length !== Object.keys(ao).length) {\n return false;\n }\n return keys.every((k) => Object.hasOwn(ao, k) && valuesEqual(eo[k], ao[k], tolerance));\n }\n return Object.is(e, a);\n}\n\n/**\n * Element-wise equality of two typed arrays.\n * @param a - one array\n * @param b - the other\n * @returns true when same length and contents\n */\nfunction typedEqual(a: ArrayLike<number>, b: ArrayLike<number>): boolean {\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * A short text of a value for messages.\n * @param v - the value\n * @returns JSON when possible, else String()\n */\nfunction show(v: unknown): string {\n if (ArrayBuffer.isView(v)) {\n const items = Array.from(v as unknown as ArrayLike<number>);\n return `[${items.slice(0, 8).join(\", \")}${items.length > 8 ? \", ...\" : \"\"}]`;\n }\n try {\n const text = JSON.stringify(v);\n return text ?? String(v);\n } catch {\n return String(v);\n }\n}\n\n/**\n * The differences compareSnapshots() found, one per line, for printing.\n * @param diffs - the differences\n * @returns one line per difference, \"no differences\" when empty\n * @category Plugin helpers\n */\nexport function describeDiffs(diffs: readonly SnapshotDiff[]): string {\n return diffs.length === 0 ? \"no differences\" : diffs.map((d) => ` - ${d.message}`).join(\"\\n\");\n}\n","/**\n * A memory guard for the builder importGraph() fills. graph-format stores every attribute as a dense\n * column, one slot per node (or edge) whether or not that element has a value, so a file whose nodes\n * each carry a differently named attribute holds n values but allocates n x n slots: a few hundred\n * kilobytes of input can need gigabytes. The guard counts the slots that hold no value and stops the\n * import once they pass a limit. A dense file has almost no empty slots, so it is never stopped\n * however large it is.\n */\n\nimport {\n type ColumnDecl,\n type ColumnHandle,\n GraphBuilder,\n type GraphBuilderOptions,\n GraphFormatError,\n type NodeId,\n} from \"@graphty/graph-format\";\n\nimport { describe } from \"./options.js\";\nimport { plural } from \"./plural.js\";\nimport { ImportReportBuilder } from \"./report.js\";\n\n/**\n * Import stopped for allocating too many empty attribute slots.\n * @category Issue and loss codes\n */\nexport const TOO_MANY_EMPTY_CELLS_CODE = \"E_TOO_MANY_EMPTY_CELLS\";\n\n/** The default limit: 2^24 empty slots, about 130 MB of f64 columns. */\nconst DEFAULT_MAX_EMPTY_CELLS = 2 ** 24;\n\n/**\n * Resolve the maxEmptyCells option.\n * @param value - the caller's value\n * @returns a non-negative integer or Infinity\n * @throws GraphFormatError E_UNSUPPORTED for anything else\n * @category Plugin helpers\n */\nexport function maxEmptyCellsOption(value: unknown): number {\n if (value === undefined) {\n return DEFAULT_MAX_EMPTY_CELLS;\n }\n if (typeof value === \"number\" && value >= 0 && (Number.isInteger(value) || value === Infinity)) {\n return value;\n }\n throw new GraphFormatError(\n \"E_UNSUPPORTED\",\n `option maxEmptyCells: ${describe(value)} is not a non-negative integer or Infinity`,\n { option: \"maxEmptyCells\", found: value },\n );\n}\n\n/**\n * A GraphBuilder that throws an ImportError once its attribute columns hold too many empty slots.\n * @category Plugin helpers\n */\nexport class CellBudgetBuilder extends GraphBuilder {\n private readonly nodeColumns = new Set<number>();\n private readonly edgeColumns = new Set<number>();\n private values = 0;\n\n /**\n * Create a builder with a limit.\n * @param options - the builder options\n * @param format - the format being read, for the error's report\n * @param maxEmptyCells - the most empty slots allowed\n */\n constructor(\n options: GraphBuilderOptions,\n private readonly format: string,\n private readonly maxEmptyCells: number,\n ) {\n super(options);\n }\n\n /**\n * Add a node, then check the limit (its row adds a slot to every node column).\n * @param id - the node id\n * @returns the node index\n */\n override addNode(id: NodeId): number {\n const index = super.addNode(id);\n this.checkBudget();\n return index;\n }\n\n /**\n * Add an edge, then check the limit (its row adds a slot to every edge column).\n * @param source - source id\n * @param target - target id\n * @param weight - the weight\n * @returns the edge index\n */\n override addEdge(source: NodeId, target: NodeId, weight?: number): number {\n const edge = super.addEdge(source, target, weight);\n this.checkBudget();\n return edge;\n }\n\n /**\n * Declare a node column, then check the limit.\n * @param decl - the declaration\n * @returns the column handle\n */\n override declareNodeColumn(decl: ColumnDecl): ColumnHandle {\n const handle = super.declareNodeColumn(decl);\n this.nodeColumns.add(handle);\n this.checkBudget();\n return handle;\n }\n\n /**\n * Declare an edge column, then check the limit.\n * @param decl - the declaration\n * @returns the column handle\n */\n override declareEdgeColumn(decl: ColumnDecl): ColumnHandle {\n const handle = super.declareEdgeColumn(decl);\n this.edgeColumns.add(handle);\n this.checkBudget();\n return handle;\n }\n\n /**\n * Set a node cell (a new name declares a column), then check the limit.\n * @param column - the handle or name\n * @param index - the node index\n * @param value - the value\n */\n override setNodeValue(column: ColumnHandle | string, index: number, value: unknown): void {\n super.setNodeValue(column, index, value);\n this.nodeColumns.add(typeof column === \"string\" ? this.nodeColumn(column) : column);\n this.count(value);\n }\n\n /**\n * Set an edge cell (a new name declares a column), then check the limit.\n * @param column - the handle or name\n * @param edge - the edge index\n * @param value - the value\n */\n override setEdgeValue(column: ColumnHandle | string, edge: number, value: unknown): void {\n super.setEdgeValue(column, edge, value);\n this.edgeColumns.add(typeof column === \"string\" ? this.edgeColumn(column) : column);\n this.count(value);\n }\n\n /**\n * Count a written value and check the budget.\n * @param value - the value; null and undefined unset a slot and do not count\n */\n private count(value: unknown): void {\n if (value !== null && value !== undefined) {\n this.values++;\n }\n this.checkBudget();\n }\n\n /**\n * Throw when the columns' slots minus the values written pass the limit.\n * @throws ImportError E_TOO_MANY_EMPTY_CELLS\n */\n private checkBudget(): void {\n const slots = this.nodeColumns.size * this.nodeBound + this.edgeColumns.size * this.edgeBound;\n const empty = slots - this.values;\n if (empty > this.maxEmptyCells) {\n new ImportReportBuilder(this.format, Infinity).fail(\n TOO_MANY_EMPTY_CELLS_CODE,\n `the attributes are too sparse: ${this.nodeColumns.size} node and ${this.edgeColumns.size} edge ` +\n `attribute columns over ${this.nodeBound} node${plural(this.nodeBound)} and ${this.edgeBound} edge${plural(this.edgeBound)} would ` +\n `allocate more than ${this.maxEmptyCells} slots that hold no value; pass a larger ` +\n `maxEmptyCells (or Infinity) to read the file anyway`,\n undefined,\n { emptyCells: empty, maxEmptyCells: this.maxEmptyCells },\n );\n }\n }\n}\n","/**\n * The built-in sources, registered as lazy sources: their descriptors are here, their code loads\n * on first use through a dynamic import of the source's subpath.\n */\n\nimport { CYPHER_DESCRIPTOR, NEO4J_DESCRIPTOR, NEPTUNE_DESCRIPTOR } from \"./cypher/descriptor.js\";\nimport {\n CYPHER_SOURCE_ID,\n NDEX_SOURCE_ID,\n NEO4J_SOURCE_ID,\n NEPTUNE_SOURCE_ID,\n OPENALEX_SOURCE_ID,\n REST_SOURCE_ID,\n} from \"./ids.js\";\nimport { NDEX_DESCRIPTOR } from \"./ndex/descriptor.js\";\nimport { OPENALEX_DESCRIPTOR, REST_DESCRIPTOR } from \"./rest/descriptor.js\";\nimport { type LazySource } from \"./types.js\";\n\n/**\n * The six built-in sources, each loading its subpath on first use.\n * @returns the lazy sources, in catalog order\n */\nexport function builtinSources(): readonly LazySource[] {\n return [\n {\n id: NDEX_SOURCE_ID,\n descriptor: NDEX_DESCRIPTOR,\n load: async () => (await import(\"./ndex/index.js\")).ndexSource,\n },\n {\n id: CYPHER_SOURCE_ID,\n descriptor: CYPHER_DESCRIPTOR,\n load: async () => (await import(\"./cypher/index.js\")).cypherSource,\n },\n {\n id: NEO4J_SOURCE_ID,\n descriptor: NEO4J_DESCRIPTOR,\n load: async () => (await import(\"./cypher/index.js\")).neo4jSource,\n },\n {\n id: NEPTUNE_SOURCE_ID,\n descriptor: NEPTUNE_DESCRIPTOR,\n load: async () => (await import(\"./cypher/index.js\")).neptuneSource,\n },\n {\n id: REST_SOURCE_ID,\n descriptor: REST_DESCRIPTOR,\n load: async () => (await import(\"./rest/index.js\")).restMappingSource,\n },\n {\n id: OPENALEX_SOURCE_ID,\n descriptor: OPENALEX_DESCRIPTOR,\n load: async () => (await import(\"./rest/index.js\")).openalexSource,\n },\n ];\n}\n","/**\n * Running a source (design sections 2, 3 and 5): the checks before any request, the three read\n * paths (`records` through the record methods, `file` through the format importers, `import`\n * straight into the sink), the caps between pages, `idPrefix`, the versioned cursor, and the\n * report's `source` member. graph-io keeps no state between calls.\n */\n\nimport { type GraphSink, INVALID_INDEX, type NodeId, type U32 } from \"@graphty/graph-format\";\n\nimport { MISSING_ID_CODE } from \"../common/codes.js\";\nimport { readBytes, throwIfAborted } from \"../common/input.js\";\nimport { ImportReportBuilder } from \"../common/report.js\";\nimport { readZipDirectory, readZipEntry } from \"../common/zip.js\";\nimport { type FormatRegistry } from \"../registry.js\";\nimport { SNIFF_HEAD_BYTES } from \"../sniff.js\";\nimport { type CommonImportOptions, ImportError, type ImportInput, type ImportReport } from \"../types.js\";\nimport { type CreatedContext, createSourceContext, detectRuntime, LimitStop } from \"./context.js\";\nimport { originOf } from \"./credentials.js\";\nimport { checkParams } from \"./define.js\";\nimport { failOn, warnOn } from \"./fail.js\";\nimport { SOURCE_FORMAT_PREFIX } from \"./ids.js\";\nimport {\n type GraphSource,\n type LoadFromSourceOptions,\n type RecordBatch,\n type SourceCursor,\n type SourceFile,\n} from \"./types.js\";\n\n/** The cursor key graph-io adds, holding the source's descriptor version. */\nconst CURSOR_VERSION_KEY = \"~v\";\n\n/** The options that belong to the source functions, never to an importer. */\nconst SOURCE_OPTION_KEYS: ReadonlySet<string> = new Set([\n \"endpoint\",\n \"credential\",\n \"cursor\",\n \"limits\",\n \"retry\",\n \"idPrefix\",\n \"allowInsecure\",\n \"fetch\",\n \"userAgent\",\n \"builder\",\n \"freeze\",\n \"onProgress\",\n \"signal\",\n]);\n\n/** The statuses whose failure on a later page keeps the pages before it. */\nconst AUTH_CODES: ReadonlySet<string> = new Set([\"E_SOURCE_AUTH\", \"E_SOURCE_FORBIDDEN\"]);\n\n/** What a call needs set up before the source runs. */\ninterface Prepared {\n /** The load's report. */\n readonly report: ImportReportBuilder;\n /** The context and its controls. */\n readonly created: CreatedContext;\n /** The params with the descriptor's defaults. */\n readonly params: Record<string, unknown>;\n /** The sink wrapper's counters, set once the sink is known. */\n readonly counts: { nodes: Set<number>; edgesAtStart: number; sink: GraphSink | null };\n}\n\n/**\n * The report format name of a source load.\n * @param id - the source id\n * @returns `\"source:<id>\"`\n */\nexport function sourceFormat(id: string): string {\n return `${SOURCE_FORMAT_PREFIX}${id}`;\n}\n\n/**\n * The cursor handed back to the caller: the source's own, with its version added.\n * @param next - the source's cursor\n * @param version - the descriptor version\n * @returns the caller's cursor\n */\nexport function wrapCursor(next: SourceCursor | null | undefined, version: number): SourceCursor | null {\n return next === null || next === undefined ? null : Object.freeze({ ...next, [CURSOR_VERSION_KEY]: version });\n}\n\n/**\n * Check every rule that holds before a request is sent and build the context.\n * @param source - the loaded source\n * @param rawParams - the caller's params\n * @param options - the caller's options\n * @param unit - what progress counts\n * @returns the report, context and params\n */\nfunction prepare(\n source: GraphSource<never>,\n rawParams: Readonly<Record<string, unknown>>,\n options: LoadFromSourceOptions,\n unit: \"items\" | \"bytes\",\n): Prepared {\n const { descriptor } = source;\n const version = descriptor?.version ?? 1;\n const report = new ImportReportBuilder(sourceFormat(source.id), options.errorLimit ?? 100);\n checkRuntime(source, report);\n checkParams(rawParams, descriptor, report);\n const params: Record<string, unknown> = {};\n for (const p of descriptor?.params ?? []) {\n if (p.default !== undefined) {\n params[p.name] = p.default;\n }\n }\n Object.assign(params, rawParams);\n\n const endpoint = resolveEndpoint(options.endpoint ?? descriptor?.defaultEndpoint ?? null, report);\n if (options.credential?.origins.length === 0 && endpoint === null) {\n failOn(report, \"E_SOURCE_PARAM\", \"a credential needs an endpoint or its own origins\", {\n name: \"credential\",\n reason: \"credential-unbound\",\n });\n }\n const cursor = resumeCursor(options.cursor, version, report);\n\n const counts: Prepared[\"counts\"] = { nodes: new Set<number>(), edgesAtStart: 0, sink: null };\n const created = createSourceContext({\n id: source.id,\n descriptor,\n options,\n report,\n endpoint,\n cursor,\n unit,\n counts: () => ({\n nodes: counts.nodes.size,\n edges: counts.sink === null ? 0 : counts.sink.edgeCount - counts.edgesAtStart,\n }),\n });\n return { report, created, params, counts };\n}\n\n/**\n * Refuse a source that cannot run here: a runtime it does not support, or a secure context it needs.\n * @param source - the loaded source\n * @param report - the load's report\n */\nfunction checkRuntime(source: GraphSource<never>, report: ImportReportBuilder): void {\n const { descriptor } = source;\n const runtime = detectRuntime();\n const support = descriptor?.runtimes?.[runtime];\n if (support?.supported === false) {\n failOn(report, \"E_SOURCE_RUNTIME\", `source ${source.id} cannot run in ${runtime}`, {\n runtime,\n reason: support.reason ?? \"unsupported\",\n });\n }\n if (\n descriptor?.needs?.secureContext === true &&\n runtime === \"browser\" &&\n (globalThis as { isSecureContext?: boolean }).isSecureContext === false\n ) {\n failOn(report, \"E_SOURCE_RUNTIME\", `source ${source.id} needs a secure context`, {\n runtime,\n reason: \"needs-secure-context\",\n });\n }\n}\n\n/**\n * The endpoint as a URL, refusing one that is not a URL or carries a user name or password.\n * @param given - the endpoint given, if any\n * @param report - the load's report\n * @returns the URL, or null without one\n */\nfunction resolveEndpoint(given: string | URL | null, report: ImportReportBuilder): URL | null {\n if (given === null) {\n return null;\n }\n let endpoint: URL;\n try {\n endpoint = new URL(given);\n } catch {\n failOn(report, \"E_SOURCE_PARAM\", \"the endpoint is not a URL\", { name: \"endpoint\", reason: \"type\" });\n }\n if (endpoint.username !== \"\" || endpoint.password !== \"\") {\n failOn(report, \"E_SOURCE_PARAM\", \"the endpoint may not carry a user name or password\", {\n name: \"endpoint\",\n reason: \"credentials-in-url\",\n });\n }\n return endpoint;\n}\n\n/**\n * The source's own cursor from the caller's, refusing one another descriptor version made.\n * @param given - the caller's cursor, if any\n * @param version - the descriptor version\n * @param report - the load's report\n * @returns the source's cursor, or null\n */\nfunction resumeCursor(\n given: SourceCursor | null | undefined,\n version: number,\n report: ImportReportBuilder,\n): SourceCursor | null {\n if (given === undefined || given === null) {\n return null;\n }\n const { [CURSOR_VERSION_KEY]: recorded, ...rest } = given;\n if (recorded !== undefined && recorded !== version) {\n failOn(report, \"E_SOURCE_PARAM\", \"the cursor was made by another version of the source\", {\n name: \"cursor\",\n reason: \"stale-cursor\",\n });\n }\n return Object.freeze(rest);\n}\n\n/**\n * Wrap a sink so every node id gets the prefix and the caps can count the distinct nodes written.\n * @param sink - the caller's sink or the builder\n * @param prepared - the call's counters\n * @param prefix - the idPrefix, if any\n * @returns the wrapped sink\n */\nexport function wrapSink(sink: GraphSink, prepared: Prepared, prefix: string | undefined): GraphSink {\n prepared.counts.sink = sink;\n prepared.counts.edgesAtStart = sink.edgeCount;\n const seen = prepared.counts.nodes;\n const id = (value: NodeId): NodeId => (prefix === undefined || prefix === \"\" ? value : `${prefix}${String(value)}`);\n const node = (index: number): number => {\n seen.add(index);\n return index;\n };\n // an edge may add its end nodes (addMissingNodes)\n const ends = (edge: number): number => {\n const [a, b] = sink.edgeEndpoints(edge);\n seen.add(a);\n seen.add(b);\n return edge;\n };\n return new Proxy(sink, {\n get(target, key): unknown {\n switch (key) {\n case \"addNode\":\n return (v: NodeId): number => node(target.addNode(id(v)));\n case \"addNodeRecord\":\n return (v: NodeId, attrs: Readonly<Record<string, unknown>>): number =>\n node(target.addNodeRecord(id(v), attrs));\n case \"addNodes\":\n return (ids: Iterable<NodeId>, out?: U32): U32 => {\n const result = target.addNodes(Array.from(ids, id), out);\n result.forEach((i) => seen.add(i));\n return result;\n };\n case \"addEdge\":\n return (s: NodeId, t: NodeId, w?: number): number => ends(target.addEdge(id(s), id(t), w));\n case \"addEdgeRecord\":\n return (\n s: NodeId,\n t: NodeId,\n attrs: Readonly<Record<string, unknown>>,\n weightKey?: string | null,\n ): number => ends(target.addEdgeRecord(id(s), id(t), attrs, weightKey));\n case \"indexOf\":\n return (v: NodeId): number => target.indexOf(id(v));\n default: {\n const value = Reflect.get(target, key, target) as unknown;\n return typeof value === \"function\" ? (value as (...a: unknown[]) => unknown).bind(target) : value;\n }\n }\n },\n });\n}\n\n/**\n * The options a format importer gets from a file source's load.\n * @param options - the caller's options\n * @param signal - the context's signal\n * @returns the importer options\n */\nfunction importerOptions(options: LoadFromSourceOptions, signal: AbortSignal): CommonImportOptions {\n const out: Record<string, unknown> = { signal };\n for (const [key, value] of Object.entries(options)) {\n if (!SOURCE_OPTION_KEYS.has(key)) {\n out[key] = value;\n }\n }\n return out;\n}\n\n/**\n * Write graph facts: `name`, `description` and `modified` strings to the graph's meta, any other\n * scalar (but `directed`) as a graph value.\n * @param sink - the sink\n * @param meta - the facts\n */\nfunction writeMeta(sink: GraphSink, meta: Readonly<Record<string, unknown>>): void {\n const patch: Record<string, string> = {};\n for (const [key, value] of Object.entries(meta)) {\n if ((key === \"name\" || key === \"description\" || key === \"modified\") && typeof value === \"string\") {\n patch[key] = value;\n } else if (\n key !== \"directed\" &&\n (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\")\n ) {\n sink.setGraphValue(key, value);\n }\n }\n if (Object.keys(patch).length > 0) {\n sink.setMeta(patch);\n }\n}\n\n/**\n * Write one page of records into the sink.\n * @param batch - the page\n * @param sink - the wrapped sink\n * @param source - the source (for its record keys)\n * @param prepared - the call\n * @param first - whether this is the first page\n */\nfunction writeBatch(\n batch: RecordBatch,\n sink: GraphSink,\n source: GraphSource<never>,\n prepared: Prepared,\n first: boolean,\n): void {\n const idKey = source.idKey ?? \"id\";\n const sourceKey = source.sourceKey ?? \"source\";\n const targetKey = source.targetKey ?? \"target\";\n const meta = batch.meta ?? {};\n if (first && typeof meta.directed === \"boolean\" && sink.edgeCount === 0) {\n sink.setDirected(meta.directed);\n }\n writeMeta(sink, meta);\n const n = writeNodes(batch, sink, idKey, prepared);\n writeEdges(batch, sink, sourceKey, targetKey, prepared, n);\n}\n\n/**\n * Write a page's node records.\n * @param batch - the page\n * @param sink - the wrapped sink\n * @param idKey - the record key holding the id\n * @param prepared - the call\n * @returns how many records were visited, for the abort check's cadence\n */\nfunction writeNodes(batch: RecordBatch, sink: GraphSink, idKey: string, prepared: Prepared): number {\n const { report } = prepared;\n const { signal } = prepared.created.ctx;\n let n = 0;\n for (const record of batch.nodes ?? []) {\n if (n++ % 64 === 0) {\n throwIfAborted(signal);\n }\n const { [idKey]: id, ...attrs } = record;\n if (typeof id !== \"string\" && typeof id !== \"number\") {\n report.error(\"missing-value\", MISSING_ID_CODE, `a node record has no ${idKey}`);\n report.counts.skippedNodes++;\n continue;\n }\n try {\n sink.addNodeRecord(id, attrs);\n report.counts.nodes++;\n } catch (err) {\n report.recordError(err, { element: String(id) });\n report.counts.skippedNodes++;\n }\n }\n return n;\n}\n\n/**\n * Write a page's edge records.\n * @param batch - the page\n * @param sink - the wrapped sink\n * @param sourceKey - the record key holding the source id\n * @param targetKey - the record key holding the target id\n * @param prepared - the call\n * @param start - records visited so far, for the abort check's cadence\n */\nfunction writeEdges(\n batch: RecordBatch,\n sink: GraphSink,\n sourceKey: string,\n targetKey: string,\n prepared: Prepared,\n start: number,\n): void {\n const { report } = prepared;\n const { signal } = prepared.created.ctx;\n let n = start;\n let edgeIds: ReturnType<GraphSink[\"declareEdgeColumn\"]> | null = null;\n for (const record of batch.edges ?? []) {\n if (n++ % 64 === 0) {\n throwIfAborted(signal);\n }\n const s = record[sourceKey];\n const t = record[targetKey];\n const edgeId = record.id;\n const fields = Object.fromEntries(\n Object.entries(record).filter(([k]) => k !== sourceKey && k !== targetKey && k !== \"id\"),\n );\n if ((typeof s !== \"string\" && typeof s !== \"number\") || (typeof t !== \"string\" && typeof t !== \"number\")) {\n report.error(\"missing-value\", MISSING_ID_CODE, `an edge record has no ${sourceKey} or ${targetKey}`);\n report.counts.skippedEdges++;\n continue;\n }\n try {\n const e = sink.addEdgeRecord(s, t, fields);\n if (typeof edgeId === \"string\" || typeof edgeId === \"number\") {\n edgeIds ??= edgeIdColumn(sink);\n sink.setEdgeValue(edgeIds, e, String(edgeId));\n }\n report.counts.edges++;\n } catch (err) {\n report.recordError(err, { element: `${String(s)} -> ${String(t)}` });\n report.counts.skippedEdges++;\n }\n }\n}\n\n/**\n * The origin of an endpoint, or \"\" without one.\n * @param endpoint - the endpoint\n * @returns its origin\n */\nfunction endpointOrigin(endpoint: URL | null): string {\n return endpoint === null ? \"\" : originOf(endpoint);\n}\n\n/**\n * The edge id column, declared on first use.\n * @param sink - the sink\n * @returns its handle\n */\nfunction edgeIdColumn(sink: GraphSink): ReturnType<GraphSink[\"declareEdgeColumn\"]> {\n const existing = sink.edgeColumn(\"id\");\n return existing === INVALID_INDEX\n ? sink.declareEdgeColumn({ name: \"id\", dtype: \"string\", role: \"id\", nullable: true })\n : existing;\n}\n\n/**\n * The page iterator of a records source: its async iterable, or its one batch.\n * @param out - what `records()` returned\n * @returns an iterator over the pages\n */\nfunction pages(out: Promise<RecordBatch> | AsyncIterable<RecordBatch>): AsyncIterator<RecordBatch> {\n if (Symbol.asyncIterator in out) {\n return out[Symbol.asyncIterator]();\n }\n let done = false;\n return {\n async next(): Promise<IteratorResult<RecordBatch>> {\n if (done) {\n return { done: true, value: undefined };\n }\n done = true;\n return { done: false, value: await out };\n },\n };\n}\n\n/**\n * Decide what a failed page means: a cap reached or a later page needing a credential stops the\n * load and keeps what was read (warning for the credential); anything else is rethrown.\n * @param err - what the page threw\n * @param page - how many pages were written before it\n * @param prepared - the call\n */\nfunction stopOrThrow(err: unknown, page: number, prepared: Prepared): void {\n if (err instanceof LimitStop) {\n return;\n }\n if (page > 0 && err instanceof ImportError && AUTH_CODES.has(String(err.issue?.code))) {\n const p = err.issue?.params ?? {};\n warnOn(prepared.report, \"W_SOURCE_AUTH\", \"a later page needs a credential; the pages before it are kept\", {\n origin: typeof p.origin === \"string\" ? p.origin : endpointOrigin(prepared.created.ctx.endpoint),\n status: typeof p.status === \"number\" ? p.status : null,\n });\n return;\n }\n throw err;\n}\n\n/**\n * Run a records source into a sink.\n * @param source - the source\n * @param sink - the wrapped sink\n * @param prepared - the call\n * @returns where to resume, as the source gave it\n */\nasync function runRecords(\n source: GraphSource<never>,\n sink: GraphSink,\n prepared: Prepared,\n): Promise<SourceCursor | null> {\n const { ctx } = prepared.created;\n const records = source.records as (p: unknown, c: typeof ctx) => Promise<RecordBatch> | AsyncIterable<RecordBatch>;\n const iterator = pages(records(prepared.params, ctx));\n let next: SourceCursor | null = ctx.cursor;\n let page = 0;\n let stopped = false;\n try {\n for (;;) {\n let step: IteratorResult<RecordBatch>;\n try {\n step = await iterator.next();\n } catch (err) {\n stopOrThrow(err, page, prepared);\n stopped = true;\n return next;\n }\n if (step.done === true) {\n return page === 0 ? null : next;\n }\n writeBatch(step.value, sink, source, prepared, page === 0);\n page++;\n next = step.value.next ?? null;\n ctx.progress(prepared.report.counts.nodes + prepared.report.counts.edges, undefined, \"items\");\n if (ctx.limits.reached()) {\n stopped = true;\n return next;\n }\n }\n } finally {\n if (stopped) {\n await iterator.return?.().catch(() => undefined);\n }\n }\n}\n\n/**\n * The importer input of a file source's body, gunzipped or unzipped when its name says so.\n * @param file - what the source returned\n * @param formats - the registry, for choosing a zip entry\n * @param signal - the signal\n * @returns the input and its hints\n */\nasync function fileInput(\n file: SourceFile,\n formats: FormatRegistry,\n signal: AbortSignal,\n): Promise<{ input: ImportInput; filename: string | undefined; mimeType: string | undefined }> {\n let input: ImportInput = file.body instanceof Response ? (file.body.body ?? new Uint8Array(0)) : file.body;\n let { filename } = file;\n let mimeType =\n file.mimeType ??\n (file.body instanceof Response ? (file.body.headers.get(\"content-type\") ?? undefined) : undefined);\n const gzip = /\\.gz$/i.test(filename ?? \"\") || /gzip/i.test(mimeType ?? \"\");\n const zip = /\\.zip$/i.test(filename ?? \"\") || /\\/(x-)?zip\\b/i.test(mimeType ?? \"\");\n if (gzip) {\n const stream =\n input instanceof ReadableStream\n ? input\n : new Response((await bytesOf(input, signal)) as Uint8Array<ArrayBuffer>).body;\n input = (stream ?? new Response(\"\").body ?? new ReadableStream()).pipeThrough(\n new DecompressionStream(\"gzip\") as unknown as ReadableWritablePair<Uint8Array, Uint8Array>,\n );\n filename = filename?.replace(/\\.gz$/i, \"\");\n mimeType = undefined;\n } else if (zip) {\n const bytes = await bytesOf(input, signal);\n const entry = readZipDirectory(bytes).find((e) => !e.directory && formats.sniff({ filename: e.name }) !== null);\n if (entry === undefined) {\n throw new ImportError(\"the zip holds no graph file\", new ImportReportBuilder(\"zip\", 0).finish());\n }\n input = await readZipEntry(bytes, entry, { signal, maxBytes: Number.MAX_SAFE_INTEGER, maxRatio: 1000 });\n filename = entry.name;\n mimeType = undefined;\n }\n return { input, filename, mimeType };\n}\n\n/**\n * The bytes of an input.\n * @param input - the input\n * @param signal - the signal\n * @returns the bytes\n */\nasync function bytesOf(input: ImportInput, signal: AbortSignal): Promise<Uint8Array> {\n return (await readBytes(input, { signal })) ?? new TextEncoder().encode(typeof input === \"string\" ? input : \"\");\n}\n\n/**\n * Run a file source into a sink through the format importers.\n * @param source - the source\n * @param sink - the wrapped sink\n * @param prepared - the call\n * @param formats - the registry\n * @param options - the caller's options\n * @returns the format the file was read as\n */\nasync function runFile(\n source: GraphSource<never>,\n sink: GraphSink,\n prepared: Prepared,\n formats: FormatRegistry,\n options: LoadFromSourceOptions,\n): Promise<string> {\n const { ctx } = prepared.created;\n const read = source.file as (p: unknown, c: typeof ctx) => Promise<SourceFile>;\n const file = await read(prepared.params, ctx);\n const { input, filename, mimeType } = await fileInput(file, formats, ctx.signal);\n let { format } = file;\n let body: ImportInput = input;\n if (format === undefined) {\n const bytes = await bytesOf(input, ctx.signal);\n format = formats.sniff({ filename, mimeType, head: bytes.subarray(0, SNIFF_HEAD_BYTES) })?.format;\n body = bytes;\n if (format === undefined) {\n failOn(prepared.report, \"E_SOURCE_RESPONSE\", \"the file is in no format graph-io reads\", {\n expected: \"graph-file\",\n contentType: mimeType ?? null,\n });\n }\n }\n const importer = formats.importer(format);\n prepared.report.include(await importer.import(body, sink, importerOptions(options, ctx.signal)));\n writeMeta(sink, file.meta ?? {});\n return format;\n}\n\n/** What a run into a sink produced. */\ninterface SinkRun {\n /** The report, with its `source` member. */\n readonly report: ImportReport;\n /** The format: `source:<id>`, or the format a file source resolved to. */\n readonly format: string;\n}\n\n/**\n * Run a source's read method into a sink.\n * @param source - the loaded source\n * @param params - the caller's params\n * @param sink - where to write\n * @param options - the caller's options\n * @param formats - the registry, for file sources\n * @returns the report and the format\n */\nexport async function runIntoSink(\n source: GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n sink: GraphSink,\n options: LoadFromSourceOptions,\n formats: FormatRegistry,\n): Promise<SinkRun> {\n const prepared = prepare(source, params, options, typeof source.file === \"function\" ? \"bytes\" : \"items\");\n const { ctx } = prepared.created;\n const version = source.descriptor?.version ?? 1;\n const wrapped = wrapSink(sink, prepared, options.idPrefix);\n try {\n if (typeof source.records === \"function\") {\n const next = await runRecords(source, wrapped, prepared);\n throwIfAborted(ctx.signal);\n return {\n report: withSource(prepared.report.finish(), prepared, wrapCursor(next, version)),\n format: sourceFormat(source.id),\n };\n }\n if (typeof source.file === \"function\") {\n const format = await runFile(source, wrapped, prepared, formats, options);\n return { report: withSource(prepared.report.finish(), prepared, null), format };\n }\n const run = source.import as (p: unknown, s: GraphSink, c: typeof ctx) => Promise<ImportReport>;\n const report = await stopAtLimit(run(prepared.params, wrapped, ctx), prepared);\n throwIfAborted(ctx.signal);\n return {\n report: withSource(report, prepared, wrapCursor(prepared.created.state.finish?.next, version)),\n format: sourceFormat(source.id),\n };\n } catch (err) {\n throw settle(err, prepared);\n } finally {\n prepared.created.dispose();\n }\n}\n\n/**\n * Run an optional method of a source (expand, probe, list, validate) with a context.\n * @param source - the loaded source\n * @param feature - the method name\n * @param params - the params checked against the descriptor\n * @param options - the caller's options\n * @param call - calls the method with the context\n * @returns what the method returned, and the call's state\n */\nexport async function runMethod<T>(\n source: GraphSource<never>,\n feature: \"expand\" | \"probe\" | \"list\" | \"validate\",\n params: Readonly<Record<string, unknown>>,\n options: LoadFromSourceOptions,\n call: (prepared: Prepared) => Promise<T>,\n): Promise<T> {\n if (typeof source[feature] !== \"function\") {\n failOn(\n new ImportReportBuilder(sourceFormat(source.id), 0),\n \"E_SOURCE_UNSUPPORTED\",\n `source ${source.id} has no ${feature}`,\n {\n feature,\n },\n );\n }\n const prepared = prepare(source, params, options, \"items\");\n try {\n const out = await call(prepared);\n throwIfAborted(prepared.created.ctx.signal);\n return out;\n } catch (err) {\n throw settle(err, prepared);\n } finally {\n prepared.created.dispose();\n }\n}\n\n/**\n * Add the `source` member to a report.\n * @param report - the report\n * @param prepared - the call\n * @param next - where to resume, as the caller sees it\n * @returns the report with its source member\n */\nexport function withSource(report: ImportReport, prepared: Prepared, next: SourceCursor | null): ImportReport {\n const own = prepared.report.finish();\n // issues the context recorded (retries, limits) that a source's own report does not hold\n const missing = own.issues.filter((i) => !report.issues.includes(i));\n return Object.freeze({\n ...report,\n issues: missing.length === 0 ? report.issues : Object.freeze([...report.issues, ...missing]),\n warningCount: report.warningCount + missing.filter((i) => i.severity === \"warning\").length,\n errorCount: report.errorCount + missing.filter((i) => i.severity === \"error\").length,\n source: prepared.created.info(next),\n });\n}\n\n/**\n * What a failed call throws: the signal's reason when it aborted, an ImportError with the source\n * info attached, or the error itself.\n * @param err - what was thrown\n * @param prepared - the call\n * @returns the error to throw\n */\nfunction settle(err: unknown, prepared: Prepared): unknown {\n const { signal } = prepared.created.ctx;\n if (signal.aborted) {\n return signal.reason as unknown;\n }\n if (err instanceof LimitStop) {\n // a cap reached where nothing can be kept (a file cut short): the load fails with the cap\n return settle(limitError(err, prepared), prepared);\n }\n if (err instanceof ImportError && err.report.source === undefined) {\n const withInfo = new ImportError(\n err.message,\n { ...err.report, source: prepared.created.info(null) },\n err.details,\n );\n withInfo.stack = err.stack;\n return withInfo;\n }\n return err;\n}\n\n/**\n * The E_SOURCE_LIMIT error of a cap that stopped a load which can keep nothing.\n * @param stop - the cap reached\n * @param prepared - the call\n * @returns the error\n */\nfunction limitError(stop: LimitStop, prepared: Prepared): unknown {\n try {\n return failOn(prepared.report, \"E_SOURCE_LIMIT\", stop.message, { limit: stop.limit, value: stop.value });\n } catch (err) {\n return err;\n }\n}\n\n/**\n * The report of an import or expand source, or, when a cap stopped it under \"stop\" (a LimitStop\n * raised by ctx.fetch that the source did not catch), the report of what it wrote so far.\n * @param run - the source's call\n * @param prepared - the call\n * @returns the report\n */\nexport async function stopAtLimit(run: Promise<ImportReport>, prepared: Prepared): Promise<ImportReport> {\n try {\n return await run;\n } catch (err) {\n if (err instanceof LimitStop) {\n return prepared.report.finish();\n }\n throw err;\n }\n}\n","/**\n * The source registry (design section 3): sources by id, in their own name space beside the\n * formats. Lazy sources are registered by descriptor and load their code on first use, so listing\n * sources loads none. A FormatRegistry holds one, so one object holds formats and sources.\n */\n\nimport { type GraphBuilder, type GraphSink } from \"@graphty/graph-format\";\n\nimport { type FormatRegistry, type ImportGraphResult } from \"../registry.js\";\nimport { type ImportReport } from \"../types.js\";\nimport { checkLazySource, checkSource } from \"./define.js\";\nimport { failAlone } from \"./fail.js\";\nimport { runIntoSink, runMethod, sourceFormat, stopAtLimit, withSource, wrapCursor, wrapSink } from \"./run.js\";\nimport {\n type ExpandRequest,\n type GraphSource,\n type LazySource,\n type LoadFromSourceOptions,\n type SourceDescriptor,\n type SourceFreshness,\n type SourceInfo,\n type SourceListing,\n type SourceListQuery,\n type SourceProbe,\n type SourceValidators,\n} from \"./types.js\";\n\n/** A registered source: loaded, or a lazy one with its descriptor. */\ninterface Entry {\n /** The descriptor known without loading. */\n readonly descriptor: SourceDescriptor;\n /** The lazy registration, if any. */\n readonly lazy: LazySource | null;\n /** The loaded source. */\n source: GraphSource<never> | null;\n /** The load in flight. */\n loading: Promise<GraphSource<never>> | null;\n}\n\n/**\n * Whether a registration is a lazy source rather than a source.\n * @param value - the registration\n * @returns true for a LazySource\n */\nfunction isLazy(value: GraphSource<never> | LazySource): value is LazySource {\n const v = value as { load?: unknown; records?: unknown; file?: unknown; import?: unknown };\n return typeof v.load === \"function\" && v.records === undefined && v.file === undefined && v.import === undefined;\n}\n\n/** What a SourceRegistry borrows from its FormatRegistry: building and freezing a graph. */\ninterface SourceBuilding {\n /**\n * A builder seeded from the load options.\n * @param options - the options\n * @param format - the report format name\n * @returns the builder\n */\n readonly newBuilder: (options: LoadFromSourceOptions, format: string) => GraphBuilder;\n /**\n * Freeze a filled builder into a load result.\n * @param format - the result's format\n * @param builder - the builder\n * @param report - the report\n * @param options - the options\n * @returns the result\n */\n readonly freeze: (\n format: string,\n builder: GraphBuilder,\n report: ImportReport,\n options: LoadFromSourceOptions,\n ) => ImportGraphResult;\n}\n\n/**\n * The sources of one FormatRegistry. Experimental.\n * @category Network sources\n */\nexport class SourceRegistry {\n private readonly entries = new Map<string, Entry>();\n\n /**\n * Create one for a format registry, whose importers read `file` sources.\n * @param formats - the format registry\n * @param building - how it builds and freezes graphs\n */\n constructor(\n private readonly formats: FormatRegistry,\n private readonly building: SourceBuilding,\n ) {}\n\n /**\n * Register a source or a lazy source. A malformed one, or an id already taken, throws an\n * ImportError with E_SOURCE_INVALID.\n * @param source - the source\n */\n register(source: GraphSource<never> | LazySource): void {\n if (isLazy(source)) {\n checkLazySource(source);\n } else {\n checkSource(source);\n }\n if (this.entries.has(source.id)) {\n failAlone(\"E_SOURCE_INVALID\", `a source with id ${source.id} is already registered`, {\n id: source.id,\n reason: \"duplicate\",\n });\n }\n const lazy = isLazy(source) ? source : null;\n this.entries.set(source.id, {\n descriptor: source.descriptor ?? { plainName: source.id, params: [] },\n lazy,\n source: lazy === null ? (source as GraphSource<never>) : null,\n loading: null,\n });\n }\n\n /**\n * Whether a source id is registered.\n * @param id - the id\n * @returns true when registered\n */\n has(id: string): boolean {\n return this.entries.has(id);\n }\n\n /**\n * Every registered source, without loading any code.\n * @returns one entry per source, in registration order\n */\n list(): readonly SourceInfo[] {\n return Object.freeze(\n [...this.entries].map(([id, e]) =>\n Object.freeze({ id, descriptor: e.descriptor, loaded: e.source !== null }),\n ),\n );\n }\n\n /**\n * A source by id, loading a lazy one; a source object passes through after its checks.\n * @param source - the id or the source\n * @returns the loaded source\n */\n async resolve(source: string | GraphSource<never>): Promise<GraphSource<never>> {\n if (typeof source !== \"string\") {\n checkSource(source);\n return source;\n }\n const entry = this.entries.get(source);\n if (entry === undefined) {\n return failAlone(\n \"E_SOURCE_UNKNOWN\",\n `no source has id ${JSON.stringify(source)}`,\n { id: source, known: [...this.entries.keys()] },\n sourceFormat(source),\n );\n }\n if (entry.source !== null) {\n return entry.source;\n }\n const lazy = entry.lazy as LazySource;\n entry.loading ??= lazy.load().then(\n (loaded) => {\n if (loaded.id !== lazy.id) {\n failAlone(\"E_SOURCE_INVALID\", `lazy source ${lazy.id} loaded a source with id ${loaded.id}`, {\n id: lazy.id,\n reason: \"lazy\",\n });\n }\n checkSource(loaded, lazy.descriptor);\n entry.source = loaded.descriptor === undefined ? { ...loaded, descriptor: lazy.descriptor } : loaded;\n return entry.source;\n },\n (err: unknown) => {\n entry.loading = null;\n throw err;\n },\n );\n return entry.loading;\n }\n\n /**\n * Load a graph from a source.\n * @param source - the id or the source\n * @param params - its params\n * @param options - endpoint, credential, cursor, caps and the import options\n * @returns the graph and the report\n */\n async load(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n options: LoadFromSourceOptions = {},\n ): Promise<ImportGraphResult> {\n const resolved = await this.resolve(source);\n const builder = this.building.newBuilder(options, sourceFormat(resolved.id));\n const { report, format } = await runIntoSink(resolved, params, builder, options, this.formats);\n return this.building.freeze(format, builder, report, options);\n }\n\n /**\n * Load from a source into a sink you own.\n * @param source - the id or the source\n * @param params - its params\n * @param sink - where to write\n * @param options - the options\n * @returns the report\n */\n async import(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n sink: GraphSink,\n options: LoadFromSourceOptions = {},\n ): Promise<ImportReport> {\n const resolved = await this.resolve(source);\n return (await runIntoSink(resolved, params, sink, options, this.formats)).report;\n }\n\n /**\n * Fetch the neighborhood of some nodes: a snapshot of only what was fetched.\n * @param source - the id or the source\n * @param request - the seeds and how far to go\n * @param options - the options\n * @returns the fetched part and the report\n */\n async expand(\n source: string | GraphSource<never>,\n request: ExpandRequest<Readonly<Record<string, unknown>>>,\n options: LoadFromSourceOptions = {},\n ): Promise<ImportGraphResult> {\n const resolved = await this.resolve(source);\n const builder: GraphBuilder = this.building.newBuilder(options, sourceFormat(resolved.id));\n const report = await runMethod(resolved, \"expand\", request.params, options, async (prepared) => {\n const sink = wrapSink(builder, prepared, options.idPrefix);\n const run = resolved.expand?.({ ...request, params: prepared.params } as never, sink, prepared.created.ctx);\n const out = await stopAtLimit(run as Promise<ImportReport>, prepared);\n return withSource(\n out,\n prepared,\n wrapCursor(prepared.created.state.finish?.next, resolved.descriptor?.version ?? 1),\n );\n });\n return this.building.freeze(sourceFormat(resolved.id), builder, report, options);\n }\n\n /**\n * Check params and credential without loading.\n * @param source - the id or the source\n * @param params - its params\n * @param options - the options\n * @returns what the service said\n */\n async probe(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n options: LoadFromSourceOptions = {},\n ): Promise<SourceProbe> {\n const resolved = await this.resolve(source);\n return runMethod(\n resolved,\n \"probe\",\n params,\n options,\n (prepared) => resolved.probe?.(prepared.params as never, prepared.created.ctx) as Promise<SourceProbe>,\n );\n }\n\n /**\n * Search what a source holds.\n * @param source - the id or the source\n * @param query - the search\n * @param options - the options\n * @returns one page of results\n */\n async search(\n source: string | GraphSource<never>,\n query: SourceListQuery<Readonly<Record<string, unknown>>>,\n options: LoadFromSourceOptions = {},\n ): Promise<SourceListing> {\n const resolved = await this.resolve(source);\n // a search narrows by some params, so required ones are not checked\n const partial: SourceDescriptor | undefined =\n resolved.descriptor === undefined\n ? undefined\n : {\n ...resolved.descriptor,\n params: resolved.descriptor.params.map((p) => ({ ...p, required: false })),\n };\n return runMethod(\n { ...resolved, descriptor: partial },\n \"list\",\n query.params,\n options,\n (prepared) =>\n resolved.list?.(\n { ...query, params: prepared.params } as never,\n prepared.created.ctx,\n ) as Promise<SourceListing>,\n );\n }\n\n /**\n * Tell whether data loaded earlier changed.\n * @param source - the id or the source\n * @param params - the params it was loaded with\n * @param seen - the validators recorded then\n * @param options - the options\n * @returns whether it changed\n */\n async validate(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n seen: SourceValidators,\n options: LoadFromSourceOptions = {},\n ): Promise<SourceFreshness> {\n const resolved = await this.resolve(source);\n return runMethod(\n resolved,\n \"validate\",\n params,\n options,\n (prepared) =>\n resolved.validate?.(prepared.params as never, seen, prepared.created.ctx) as Promise<SourceFreshness>,\n );\n }\n}\n","/**\n * The importer / exporter registry: the built-in formats\n * registered by name, `sniff()` over them, and the two conveniences for callers who do not own a\n * sink: `importGraph()` sniffs the format, creates a builder seeded from the common options\n * (`directed: true` as a placeholder; the importer sets the real value), imports and freezes;\n * `exportGraph()` looks the exporter up by name. A caller who owns a builder uses the importer\n * objects directly (the subpath exports) and this module never touches their sink.\n */\n\nimport {\n type FreezeOptions,\n type FreezeReport,\n GraphBuilder,\n type GraphBuilderOptions,\n GraphFormatError,\n type GraphSink,\n type GraphSnapshot,\n} from \"@graphty/graph-format\";\n\nimport { CellBudgetBuilder, maxEmptyCellsOption } from \"./common/cell-budget.js\";\nimport {\n EDGES_MERGED_CODE,\n EMPTY_INPUT_CODE,\n FETCH_CODE,\n OPTION_IGNORED_CODE,\n SELF_LOOPS_DROPPED_CODE,\n STYLES_NOT_IMPORTED_CODE,\n UNKNOWN_OPTION_CODE,\n WEIGHT_NOT_FOUND_CODE,\n} from \"./common/codes.js\";\nimport { abortable, foreignKind, lockReader, normalizeInput, throwIfAborted } from \"./common/input.js\";\nimport { chooseGraph, resolveImportOptions } from \"./common/options.js\";\nimport { agree, plural } from \"./common/plural.js\";\nimport { ImportReportBuilder, isAbortError, messageOf } from \"./common/report.js\";\nimport { collectBytes } from \"./common/writer.js\";\nimport { csvExporter, csvImporter } from \"./formats/csv/index.js\";\nimport { cxExporter, cxImporter } from \"./formats/cx/index.js\";\nimport { cx2Exporter, cx2Importer } from \"./formats/cx2/index.js\";\nimport { cysExporter, cysImporter } from \"./formats/cys/index.js\";\nimport { dotExporter, dotImporter } from \"./formats/dot/index.js\";\nimport { gexfExporter, gexfImporter } from \"./formats/gexf/index.js\";\nimport { gmlExporter, gmlImporter } from \"./formats/gml/index.js\";\nimport { graphmlExporter, graphmlImporter } from \"./formats/graphml/index.js\";\nimport { jsonExporter, jsonImporter } from \"./formats/json/index.js\";\nimport { neo4jExporter, neo4jImporter } from \"./formats/neo4j/index.js\";\nimport { oboExporter, oboImporter } from \"./formats/obo/index.js\";\nimport { pajekExporter, pajekImporter } from \"./formats/pajek/index.js\";\nimport { xgmmlExporter, xgmmlImporter } from \"./formats/xgmml/index.js\";\nimport { type FormatName, rankFormats, SNIFF_HEAD_BYTES, type SniffHints, type SniffResult } from \"./sniff.js\";\nimport { builtinSources } from \"./sources/builtins.js\";\nimport { type SourceParamsMap } from \"./sources/params.js\";\nimport { SourceRegistry } from \"./sources/registry.js\";\nimport {\n type ExpandRequest,\n type GraphSource,\n type LazySource,\n type LoadFromSourceOptions,\n type SourceFreshness,\n type SourceInfo,\n type SourceListing,\n type SourceListQuery,\n type SourceProbe,\n type SourceValidators,\n} from \"./sources/types.js\";\nimport { extractStyles, type StyleImportOptions } from \"./styles/io/generic.js\";\nimport { isKeptGraphtyProperty, prepareStyleExport } from \"./styles/io/writer.js\";\nimport type { ExtractedStyles } from \"./styles/types.js\";\nimport {\n type CommonExportOptions,\n type CommonImportOptions,\n type ExportCapabilities,\n type GraphChoiceOptions,\n type GraphExporter,\n type GraphImporter,\n type GraphListing,\n ImportError,\n type ImportInput,\n type ImportIssue,\n type ImportReport,\n type IssueCategory,\n type LossNote,\n} from \"./types.js\";\n\n/**\n * The input is in no format graph-io can read (or none of the formats you registered, for your own FormatRegistry).\n * Pass `format` when you know what the file is.\n * @category Issue and loss codes\n */\nexport const UNKNOWN_FORMAT_CODE = \"E_UNKNOWN_FORMAT\";\n\n/**\n * Registered importer whose sniff() threw while the format was being chosen; that importer was treated as not\n * recognizing the input (a defect in that importer).\n * @category Issue and loss codes\n */\nexport const SNIFF_FAILED_CODE = \"W_SNIFF_FAILED\";\n\n/**\n * The `builder` option of importGraph(): settings for building the graph that the common import\n * options do not cover. `weighted`: \"auto\" (the default) gives the graph weights when any edge has\n * one, true always does (every weight 1 when the file has none), false never does. `expectedNodes`\n * and `expectedEdges`: how many nodes and edges to make room for up front, which saves time on a\n * large file whose size you know.\n * @category Loading\n */\nexport type BuilderSeed = Omit<\n GraphBuilderOptions,\n \"directed\" | \"addMissingNodes\" | \"duplicateEdges\" | \"selfLoops\" | \"weightDtype\"\n>;\n\n/**\n * The options of importGraph(), importAllGraphs(), listGraphs() and loadFromFile(): the common\n * import options, the format and the hints used to detect it, the graph to read from a file that\n * holds several, and any format-specific option (`delimiter`, `dialect`, ...), which reaches the\n * importer unchanged.\n * @category Loading\n */\nexport interface ImportGraphOptions extends CommonImportOptions, GraphChoiceOptions {\n /**\n * The format to read the input as (\"graphml\", \"csv\", ...; `listFormats()` names them all), or\n * \"auto\" to work it out from `filename`, `mimeType` and the first bytes of the input. Name it to\n * be strict: detection reads a file graph-io cannot place as the closest format it recognizes.\n * @defaultValue \"auto\"\n */\n readonly format?: FormatName | \"auto\" | undefined;\n /**\n * The file name or full path the input came from; only its extension is used, as a format hint.\n * loadFromUrl() takes it from the URL and loadFromFile() from a File's name when you do not pass\n * it.\n */\n readonly filename?: string | null | undefined;\n /**\n * The MIME type the input was served as, a format hint. loadFromUrl() takes it from the\n * response's Content-Type and loadFromFile() from the Blob's `type` when you do not pass it.\n */\n readonly mimeType?: string | null | undefined;\n /**\n * Settings for building the graph: `weighted` (\"auto\", true or false: whether the graph gets\n * weights), `expectedNodes` and `expectedEdges` (room to make up front for a large file). Most\n * programs never set it.\n */\n readonly builder?: BuilderSeed | undefined;\n /**\n * Settings for the last step of an import, which turns what was read into the snapshot:\n * `label` (a name for debugging, read back as `snapshot.label`), `prepare` (views of the graph\n * to compute up front, such as `[\"reverse\"]`), `checksum` (record checksums, which\n * `snapshot.validate({ checksum: true })` compares later to catch changed memory) and `profile` (record how long each step took, in `result.freeze.timings`). Most\n * programs never set it.\n */\n readonly freeze?: FreezeOptions | undefined;\n /**\n * The most attribute slots that hold no value the import may allocate before it stops with an\n * ImportError whose `issue.code` is E_TOO_MANY_EMPTY_CELLS. Every attribute is a column with one slot per node (or edge), so a file\n * whose nodes each have a differently named attribute would otherwise need nodes x attributes\n * memory. Infinity turns the check off. Files whose elements mostly share their attributes are\n * never stopped.\n * @defaultValue 16777216\n */\n readonly maxEmptyCells?: number | undefined;\n /**\n * Read the file's styles too: `true`, or `{ toolDefaults: false }` to leave out the defaults of the program\n * that wrote the file. The styles are in `result.styles`; the graph, the report and every export are the same\n * either way.\n * @defaultValue false\n */\n readonly styles?: boolean | StyleImportOptions | undefined;\n /** Format-specific options, passed to the importer as they are. */\n readonly [formatOption: string]: unknown;\n}\n\n/**\n * What importGraph(), loadFromUrl() and loadFromFile() return.\n * @category Loading\n */\nexport interface ImportGraphResult {\n /** The format the input was read as (\"graphml\", ...). */\n readonly format: string;\n /**\n * How the format was detected (the candidate's `confidence` and what matched), or null when you\n * named the format. Most callers can ignore it. For the JSON dialect that was read, call\n * `jsonShapeOf(snapshot)` from `@graphty/graph-io/json`.\n */\n readonly sniff: SniffResult | null;\n /**\n * The graph. `snapshot.nodeCount`, `snapshot.edgeCount`, attribute tables and so on come from\n * the `@graphty/graph-format` package.\n */\n readonly snapshot: GraphSnapshot;\n /**\n * What happened during the import. `errorCount` counts skipped elements (see `errorLimit`,\n * default 100); `warningCount` counts elements that were kept but changed; `issues` lists both;\n * `counts.skippedNodes` / `counts.skippedEdges` say how much is missing from `snapshot`.\n */\n readonly report: ImportReport;\n /**\n * What the last step of the import did to the graph: `mergedEdges` (parallel edges merged by\n * `duplicateEdges`), `droppedSelfLoops` (removed by `selfLoops: \"drop\"`), and `timings` when you\n * passed `freeze: { profile: true }`. Both counts are also reported as warnings, so most callers\n * can ignore it. It is not enumerable, so `console.log(result)` and `{ ...result }` leave it out.\n */\n readonly freeze: FreezeReport;\n /**\n * The file's styles, when you passed the `styles` option: the rules that reproduce how the program that wrote\n * the file draws each node and edge, read by the importer that read the file. Null when the file has none.\n * Absent without the option.\n */\n readonly styles?: ExtractedStyles | null;\n}\n\n/**\n * Options for loadFromUrl(): everything importGraph() accepts, plus the fetch request settings.\n * @example\n * ```ts\n * await loadFromUrl(\"/api/graph.csv\", { request: { headers: { Authorization: token } }, delimiter: \";\" });\n * ```\n * @category Loading\n */\nexport interface LoadFromUrlOptions extends ImportGraphOptions {\n /**\n * Passed to fetch() as its second argument: headers, credentials, mode and so on. If you set\n * `signal` in the import options and not here, the same signal also cancels the download.\n */\n readonly request?: RequestInit | undefined;\n}\n\n/**\n * Options for downloadGraph(): the export options plus the name of the saved file.\n * @example\n * ```ts\n * await downloadGraph(snapshot, \"graphml\", { filename: \"network.graphml\" });\n * ```\n * @category Saving\n */\nexport interface DownloadGraphOptions extends ExportGraphOptions {\n /**\n * The file name the browser saves as. The default is \"graph\" plus the first entry of the\n * format's `extensions` (\"graph.graphml\"), or \"graph.<format>\" when it lists none.\n * @defaultValue \"graph\" plus the format's extension\n */\n readonly filename?: string | undefined;\n}\n\n/**\n * One format the registry can read, write or both.\n * @category Formats and detection\n */\nexport interface FormatInfo {\n /** The name you pass as `format`: \"graphml\", \"gexf\", \"csv\", \"pajek\", ... */\n readonly format: string;\n /**\n * File extensions with the leading dot, most common first (\".graphml\", \".net\"). Empty only for a\n * custom format that declares none.\n */\n readonly extensions: readonly string[];\n /** MIME types, most specific first. Empty when the format declares none. */\n readonly mimeTypes: readonly string[];\n /** Whether loadFromUrl(), loadFromFile() and importGraph() can read it. */\n readonly canImport: boolean;\n /** Whether the export functions can write it. */\n readonly canExport: boolean;\n /**\n * What the format can store exactly, or null when it cannot be written. The fields are\n * mixedDirection, multiEdges, selfLoops, edgeIds, idCharset, dtypes, components, lists, json,\n * defaults, options, hierarchy, temporal, graphAttributes, positions and viz (each documented on\n * ExportCapabilities). checkExport() tells you where a particular graph goes beyond this.\n */\n readonly capabilities: ExportCapabilities | null;\n}\n\n/**\n * The options of exportGraph(): the common export options plus any format-specific option, passed through.\n * @category Saving\n */\nexport interface ExportGraphOptions extends CommonExportOptions {\n /**\n * Write these styles too (`result.styles` of an import, or styles built for this graph): each element's look in\n * the format's own style slots and, where the format can keep them, the rules, so importing the file back\n * rebuilds them. What the format cannot hold is a W_STYLE_ note of checkExport(). Styles read from or built for a\n * different graph fail with E_STYLES_MISMATCH before anything is written.\n */\n readonly styles?: ExtractedStyles | null | undefined;\n /** Format-specific options, passed to the exporter as they are. */\n readonly [formatOption: string]: unknown;\n}\n\n/**\n * The options the load and save functions take themselves: the common import and export options and the functions'\n * own. With the formats' own `options` lists, these are the names a load or a save knows.\n */\nconst FUNCTION_OPTIONS: ReadonlySet<string> = new Set([\n \"addMissingNodes\",\n \"builder\",\n \"defaultDirected\",\n \"duplicateEdges\",\n \"encoding\",\n \"errorLimit\",\n \"filename\",\n \"format\",\n \"freeze\",\n \"graphIndex\",\n \"graphName\",\n \"hyperedges\",\n \"ids\",\n \"long\",\n \"maxEmptyCells\",\n \"mimeType\",\n \"nodeIdFrom\",\n \"onMixedDirection\",\n \"onProgress\",\n \"request\",\n \"restoreMangledIds\",\n \"sanitizeIds\",\n \"selfLoops\",\n \"signal\",\n \"styles\",\n \"weightDtype\",\n \"weightFrom\",\n]);\n\n/** The keys of ImportGraphOptions that belong to the registry, never to an importer. */\nconst REGISTRY_KEYS: ReadonlySet<string> = new Set([\n \"format\",\n \"filename\",\n \"mimeType\",\n \"builder\",\n \"freeze\",\n \"maxEmptyCells\",\n \"styles\",\n]);\n\n/**\n * A registry of importers and exporters by format name. Registration order is the tie-break\n * order of sniffing; the default registry lists the built-in formats in the\n * order of GRAPH_FORMATS.\n * @category Formats and detection\n */\nexport class FormatRegistry {\n private readonly importerMap = new Map<string, GraphImporter>();\n\n private readonly exporterMap = new Map<string, GraphExporter>();\n\n private readonly sources = new SourceRegistry(this, {\n newBuilder: (options, format) => seededBuilder(options as ImportGraphOptions, format),\n freeze: (format, builder, report, options) =>\n result(\n { importer: { format } as GraphImporter, sniff: null, source: \"\", peeked: null, warnings: [] },\n builder,\n report,\n options as ImportGraphOptions,\n ),\n });\n\n /**\n * Register a network source, or a lazy one whose code loads on first use. Source ids are their\n * own name space, apart from format names. Throws an ImportError with E_SOURCE_INVALID for a\n * malformed source or an id already taken. Experimental.\n * @param source - the source\n * @returns this registry\n */\n registerSource<P>(source: GraphSource<P> | LazySource): this {\n this.sources.register(source);\n return this;\n }\n\n /**\n * A registered source by id, its code loaded. Rejects with E_SOURCE_UNKNOWN for an id no\n * source has. Experimental.\n * @param id - the source id\n * @returns the source\n */\n source(id: string): Promise<GraphSource<never>> {\n return this.sources.resolve(id);\n }\n\n /**\n * Whether a source id is registered. Experimental.\n * @param id - the source id\n * @returns true when registered\n */\n hasSource(id: string): boolean {\n return this.sources.has(id);\n }\n\n /**\n * Every registered source with its descriptor, loading no source code. Experimental.\n * @returns one entry per source\n */\n listSources(): readonly SourceInfo[] {\n return this.sources.list();\n }\n\n /**\n * Load a graph from a network source; see the top-level loadFromSource(). Experimental.\n * @param source - the source id or the source\n * @param params - its params\n * @param options - endpoint, credential, cursor, caps and import options\n * @returns the graph and the report\n */\n loadFromSource(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n options?: LoadFromSourceOptions,\n ): Promise<ImportGraphResult> {\n return this.sources.load(source, params, options);\n }\n\n /**\n * Load from a network source into a sink you own. Experimental.\n * @param source - the source id or the source\n * @param params - its params\n * @param sink - where to write\n * @param options - the options\n * @returns the report\n */\n importFromSource(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n sink: GraphSink,\n options?: LoadFromSourceOptions,\n ): Promise<ImportReport> {\n return this.sources.import(source, params, sink, options);\n }\n\n /**\n * Fetch the neighborhood of some nodes from a network source. Experimental.\n * @param source - the source id or the source\n * @param request - the seeds and how far to go\n * @param options - the options\n * @returns a graph of only what was fetched\n */\n expandFromSource(\n source: string | GraphSource<never>,\n request: ExpandRequest<Readonly<Record<string, unknown>>>,\n options?: LoadFromSourceOptions,\n ): Promise<ImportGraphResult> {\n return this.sources.expand(source, request, options);\n }\n\n /**\n * Check a source's params and credential without loading. Experimental.\n * @param source - the source id or the source\n * @param params - its params\n * @param options - the options\n * @returns what the service said\n */\n probeSource(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n options?: LoadFromSourceOptions,\n ): Promise<SourceProbe> {\n return this.sources.probe(source, params, options);\n }\n\n /**\n * Search what a source holds. Experimental.\n * @param source - the source id or the source\n * @param query - the search\n * @param options - the options\n * @returns one page of results\n */\n listFromSource(\n source: string | GraphSource<never>,\n query: SourceListQuery<Readonly<Record<string, unknown>>>,\n options?: LoadFromSourceOptions,\n ): Promise<SourceListing> {\n return this.sources.search(source, query, options);\n }\n\n /**\n * Tell whether data loaded from a source changed. Experimental.\n * @param source - the source id or the source\n * @param params - the params it was loaded with\n * @param seen - the validators recorded then (`report.source.validators`)\n * @param options - the options\n * @returns whether it changed\n */\n validateSource(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n seen: SourceValidators,\n options?: LoadFromSourceOptions,\n ): Promise<SourceFreshness> {\n return this.sources.validate(source, params, seen, options);\n }\n\n /**\n * Register an importer under its format name, replacing one of the same name in place (the\n * original registration order is kept).\n * @param importer - the importer\n * @returns this registry, for chaining\n */\n registerImporter(importer: GraphImporter): this {\n this.importerMap.set(importer.format, importer);\n return this;\n }\n\n /**\n * Register an exporter under its format name, replacing one of the same name.\n * @param exporter - the exporter\n * @returns this registry, for chaining\n */\n registerExporter(exporter: GraphExporter): this {\n this.exporterMap.set(exporter.format, exporter);\n return this;\n }\n\n /**\n * The importer of a format.\n * @param format - the format name\n * @returns the importer; E_UNSUPPORTED when none is registered\n */\n importer(format: FormatName): GraphImporter {\n const importer = this.importerMap.get(format);\n if (importer === undefined) {\n throw unknownFormat(\"importer\", format, this.importerMap.keys());\n }\n return importer;\n }\n\n /**\n * The exporter of a format.\n * @param format - the format name\n * @returns the exporter; E_UNSUPPORTED when none is registered\n */\n exporter(format: FormatName): GraphExporter {\n const exporter = this.exporterMap.get(format);\n if (exporter === undefined) {\n throw unknownFormat(\"exporter\", format, this.exporterMap.keys());\n }\n return exporter;\n }\n\n /**\n * Whether an importer is registered for a format.\n * @param format - the format name\n * @returns true when importer(format) would succeed\n */\n hasImporter(format: FormatName): boolean {\n return this.importerMap.has(format);\n }\n\n /**\n * Whether an exporter is registered for a format.\n * @param format - the format name\n * @returns true when exporter(format) would succeed\n */\n hasExporter(format: FormatName): boolean {\n return this.exporterMap.has(format);\n }\n\n /**\n * Every registered importer, in registration order.\n * @returns the importers\n */\n importers(): readonly GraphImporter[] {\n return [...this.importerMap.values()];\n }\n\n /**\n * Every registered exporter, in registration order.\n * @returns the exporters\n */\n exporters(): readonly GraphExporter[] {\n return [...this.exporterMap.values()];\n }\n\n /**\n * The names of every format with an importer or an exporter, importers' order first.\n * @returns the format names, each once\n */\n formats(): readonly string[] {\n return [...new Set([...this.importerMap.keys(), ...this.exporterMap.keys()])];\n }\n\n /**\n * Every format that could be the input, best first, from the same hints as sniff(): use it to\n * offer the user a choice when the best guess is not certain.\n * @param hints - `{ filename, mimeType, head }`, any of them\n * @returns the candidates, best first; empty when no format claims the input\n */\n sniffAll(hints: SniffHints): readonly SniffResult[] {\n return rankFormats(hints, this.importerMap.values());\n }\n\n /**\n * The best importer for an input, or null when no registered importer claims it.\n * @param hints - the filename, MIME type and / or head of the input\n * @returns the best candidate, or null\n */\n sniff(hints: SniffHints): SniffResult | null {\n const ranked = this.sniffAll(hints);\n return ranked.length > 0 ? ranked[0] : null;\n }\n\n /**\n * Read a graph from a string, bytes or a stream. The format is the one you name in `format`,\n * else it is detected from `filename`, `mimeType` and the first bytes of the content. From an\n * input that holds several graphs, it reads the one `graphIndex` or `graphName` chooses, else\n * the first, with a W_MULTIPLE_GRAPHS warning; importAllGraphs() returns every one.\n * @param input - the text, bytes, stream or chunks to read\n * @param options - the format, hints, common and format-specific import options\n * @returns the graph (`snapshot`), the format it was read as, and the import report\n */\n async importGraph(\n input: ImportInput,\n options: ImportGraphOptions | CommonImportOptions = {},\n ): Promise<ImportGraphResult> {\n const opts = options as ImportGraphOptions;\n const picked = await this.choose(input, opts);\n const unknown = this.unknownOptions(opts).map((name): ImportIssue =>\n Object.freeze({\n category: \"unsupported\",\n severity: \"warning\",\n code: UNKNOWN_OPTION_CODE,\n message: unknownOptionText(name),\n line: null,\n element: name,\n }),\n );\n const chosen = unknown.length === 0 ? picked : { ...picked, warnings: [...picked.warnings, ...unknown] };\n const { importer } = chosen;\n if (\n (opts.graphIndex !== undefined || opts.graphName !== undefined) &&\n importer.importAll !== undefined &&\n importer.listGraphs === undefined\n ) {\n // an importer that reads several graphs but does not choose among them itself (DOT, GML,\n // Pajek): read them all and return the chosen one, so the choice is never ignored\n const all = await this.readAll(chosen, opts);\n const names = all.map((r) => r.snapshot.meta.name);\n return all[chooseGraph(names, opts, new ImportReportBuilder(importer.format, 0))];\n }\n let builder: GraphBuilder;\n let report: ImportReport;\n try {\n builder = seededBuilder(opts, chosen.importer.format);\n report = await chosen.importer.import(chosen.source, builder, importerOptions(opts));\n } catch (err) {\n await chosen.peeked?.close();\n throw chosen.sniff === null ? notReadableAs(err, importer.format, opts.filename) : err;\n }\n return result(chosen, builder, report, opts);\n }\n\n /**\n * Fetch a graph file from a URL and load it; see the top-level loadFromUrl() for the full\n * description.\n * @param url - an absolute URL, or in a browser one relative to the page\n * @param options - import options, plus `request` for fetch\n * @returns the graph, the format it was read as, and the import report\n */\n async loadFromUrl(\n url: string | URL,\n options: LoadFromUrlOptions | CommonImportOptions = {},\n ): Promise<ImportGraphResult> {\n const opts = options as LoadFromUrlOptions;\n const { request, ...rest } = opts;\n const signal = request?.signal ?? rest.signal ?? null;\n const method = request?.method ?? \"GET\";\n const where = `${method} ${String(url)}`;\n let response: Response;\n try {\n response = await fetch(url, { signal: rest.signal, ...request });\n } catch (err) {\n if (signal?.aborted === true || isAbortError(err)) {\n throw err;\n }\n return fetchFailed(rest, url, `${where} failed: ${fetchErrorText(url, err)}`, null, err);\n }\n if (!response.ok) {\n await response.body?.cancel().catch(() => undefined);\n const status = `${String(response.status)} ${response.statusText}`.trim();\n return fetchFailed(rest, url, `${where} failed: ${status}`, response.status, null);\n }\n return this.importGraph(response.body ?? new Uint8Array(0), {\n ...rest,\n filename: rest.filename ?? urlFilename(url),\n mimeType: rest.mimeType ?? response.headers.get(\"content-type\"),\n });\n }\n\n /**\n * Load a graph from a File or Blob; see the top-level loadFromFile() for the full description.\n * @param file - the File or Blob to read\n * @param options - the same options as importGraph()\n * @returns the graph, the format it was read as, and the import report\n */\n loadFromFile(file: Blob, options: ImportGraphOptions | CommonImportOptions = {}): Promise<ImportGraphResult> {\n const opts = options as ImportGraphOptions;\n const { name } = file as { name?: unknown };\n return this.importGraph(file.stream(), {\n ...opts,\n filename: opts.filename ?? (typeof name === \"string\" ? name : null),\n mimeType: opts.mimeType ?? (file.type === \"\" ? null : file.type),\n });\n }\n\n /**\n * Read every graph of an input (a DOT file with several graphs, a Pajek project with several\n * networks, a JGF document with a `graphs` array), each as its own snapshot. A format that holds\n * one graph per file gives one result. Options and detection are those of importGraph().\n * @param input - the text, bytes, stream or chunks to read\n * @param options - the format, hints, common and format-specific import options\n * @returns one result per graph, in document order\n */\n async importAllGraphs(\n input: ImportInput,\n options: ImportGraphOptions | CommonImportOptions = {},\n ): Promise<ImportGraphResult[]> {\n const opts = options as ImportGraphOptions;\n return this.readAll(await this.choose(input, opts), opts);\n }\n\n /**\n * Read every graph of an input with the chosen importer.\n * @param chosen - the importer and the input to hand it\n * @param options - the importGraph options\n * @returns one result per graph, in document order\n */\n private async readAll(chosen: ChosenImporter, options: ImportGraphOptions): Promise<ImportGraphResult[]> {\n const { importer } = chosen;\n const builders: GraphBuilder[] = [];\n let reports: ImportReport[];\n try {\n if (importer.importAll === undefined) {\n builders.push(seededBuilder(options, importer.format));\n reports = [await importer.import(chosen.source, builders[0], importerOptions(options))];\n } else {\n reports = await importer.importAll(\n chosen.source,\n () => {\n const builder = seededBuilder(options, importer.format);\n builders.push(builder);\n return builder;\n },\n importerOptions(options),\n );\n }\n } catch (err) {\n await chosen.peeked?.close();\n throw inGraph(\n chosen.sniff === null ? notReadableAs(err, importer.format, options.filename) : err,\n builders.length - 1,\n );\n }\n return reports.map((report, i) => {\n try {\n return result(chosen, builders[i], report, options);\n } catch (err) {\n throw inGraph(err, i);\n }\n });\n }\n\n /**\n * The graphs of an input that can hold several, without importing them (a Cytoscape session's\n * networks, a JGF `graphs` array), so a caller can offer a choice and then pass `graphIndex`\n * or `graphName` to importGraph(). The format is named or sniffed as by importGraph().\n * @param input - the text, bytes, stream or chunks to read\n * @param options - the format, hints, common and format-specific import options\n * @returns one listing per graph, in document order; null when the format's importer does not\n * list its graphs (importGraph() then reads the first)\n */\n async listGraphs(\n input: ImportInput,\n options: ImportGraphOptions | CommonImportOptions = {},\n ): Promise<readonly GraphListing[] | null> {\n const opts = options as ImportGraphOptions;\n const chosen = await this.choose(input, opts);\n try {\n return chosen.importer.listGraphs === undefined\n ? null\n : await chosen.importer.listGraphs(chosen.source, importerOptions(opts));\n } finally {\n await chosen.peeked?.close();\n }\n }\n\n /**\n * The importer for an input: the named format, or the sniffed one.\n * @param rawInput - the input as the caller passed it\n * @param options - the importGraph options\n * @returns the importer, the sniff, and the input to read (replayed for a stream)\n */\n private async choose(rawInput: ImportInput, options: ImportGraphOptions): Promise<ChosenImporter> {\n const input = normalizeInput(rawInput);\n const requested = options.format ?? \"auto\";\n if (requested !== \"auto\") {\n return { importer: this.importer(requested), sniff: null, source: input, peeked: null, warnings: [] };\n }\n // the options are checked before the input is touched, so a bad option never leaves a\n // peeked stream locked; the importer resolves them again with its own defaults\n const common = resolveImportOptions(options, { ids: \"keep\", defaultDirected: true, weightFrom: null });\n maxEmptyCellsOption(options.maxEmptyCells);\n const peeked = await peekHead(input, SNIFF_HEAD_BYTES, common.signal);\n // the head is sniffed as the importer will read it: in the caller's encoding when given\n const head =\n common.encoding !== null && peeked.head instanceof Uint8Array\n ? new TextDecoder(common.encoding).decode(peeked.head, { stream: true })\n : peeked.head;\n let sniff: SniffResult | null;\n const failures = new ImportReportBuilder(\"unknown\", 0);\n const warnings: ImportIssue[] = [];\n try {\n const hints = { filename: options.filename, mimeType: options.mimeType, head };\n const ranked = rankFormats(hints, this.importerMap.values(), (format, err) => {\n warnings.push(\n failures.warning(\n \"unsupported\",\n SNIFF_FAILED_CODE,\n `the ${format} importer's sniff() threw (${messageOf(err)}); it was treated as not recognizing the input`,\n { element: format },\n ),\n );\n });\n sniff = ranked.length > 0 ? ranked[0] : null;\n } catch (err) {\n await peeked.close();\n throw err;\n }\n // a known non-graph file is refused whatever its name says, unless an importer claims its\n // content (a Cytoscape session is a zip); an HTML page always (the XML sniffers would\n // otherwise claim it by its markup)\n const foreign = foreignKind(peeked.head);\n const claimed = sniff !== null && sniff.content > 0 && !(foreign?.startsWith(\"an HTML\") ?? false);\n if (sniff === null || (foreign !== null && !claimed)) {\n await peeked.close();\n return this.refuseUndetected(failures, head, foreign, options);\n }\n return { importer: this.importer(sniff.format), sniff, source: peeked.input, peeked, warnings };\n }\n\n /**\n * Refuse an input no importer recognizes: empty, or not in a known graph format.\n * @param failures - the report the error is recorded in\n * @param head - the head, as sniffed\n * @param foreign - what known non-graph file the head is, or null\n * @param options - the importGraph options\n * @returns never: always throws\n */\n private refuseUndetected(\n failures: ImportReportBuilder,\n head: Uint8Array | string | null,\n foreign: string | null,\n options: ImportGraphOptions,\n ): never {\n const text = typeof head === \"string\" ? head : new TextDecoder().decode(head ?? new Uint8Array(0));\n if (text.trim() === \"\" && text.length < SNIFF_HEAD_BYTES) {\n // nothing to detect: say the input is empty, as a named format would\n return failures.fail(\n EMPTY_INPUT_CODE,\n text === \"\" ? \"the input is empty\" : \"the input holds only whitespace\",\n );\n }\n const what = foreign === null ? \"\" : `: it is ${foreign}`;\n return failures.fail(\n UNKNOWN_FORMAT_CODE,\n `the input is not in a graph format graph-io recognizes${describeHints(options)}${what}; if you know its format, pass it as the format option`,\n undefined,\n { formats: this.formats() },\n );\n }\n\n /**\n * Write a snapshot in a format, as UTF-8 chunks.\n * @param snapshot - the snapshot\n * @param format - the format name\n * @param options - the exporter's common and format-specific options\n * @returns the encoded chunks\n */\n exportGraph(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n ): AsyncIterable<Uint8Array> {\n const styled = this.styled(snapshot, format, options);\n if (styled === null) {\n return this.exporter(format).export(snapshot, options);\n }\n if (styled.refusal !== null) {\n return refuse(styled.refusal);\n }\n return styled.exporter.export(styled.snapshot, styled.options);\n }\n\n /**\n * An export with styles worked out, or null when no styles were given (the export is then exactly as before).\n * @param snapshot - the graph\n * @param format - the format name\n * @param options - the caller's options\n * @returns the exporter, the snapshot and options to hand it, the style losses and any refusal\n */\n private styled(\n snapshot: GraphSnapshot,\n format: FormatName,\n options: ExportGraphOptions | CommonExportOptions | undefined,\n ): StyledExport | null {\n const styles = (options as ExportGraphOptions | undefined)?.styles;\n if (styles === undefined || styles === null) {\n return null;\n }\n const exporter = this.exporter(format);\n const { styles: _given, ...rest } = options as ExportGraphOptions;\n const prepared = prepareStyleExport(snapshot, exporter, styles, rest);\n return {\n exporter,\n snapshot: prepared.snapshot,\n options: prepared.input === null ? rest : { ...rest, styles: prepared.input },\n plain: rest,\n notes: prepared.notes,\n refusal: prepared.refusal,\n };\n }\n\n /**\n * Write a snapshot in a format, as one string.\n * @param snapshot - the snapshot\n * @param format - the format name\n * @param options - the exporter's common and format-specific options\n * @returns the whole document\n */\n async exportGraphToString(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n ): Promise<string> {\n const styled = this.styled(snapshot, format, options);\n if (styled === null) {\n return this.exporter(format).exportToString(snapshot, options);\n }\n if (styled.refusal !== null) {\n throw refusalError(styled.refusal);\n }\n return styled.exporter.exportToString(styled.snapshot, styled.options);\n }\n\n /**\n * Write a snapshot in a format as one buffer of UTF-8 bytes; see the top-level\n * exportGraphToBytes().\n * @param snapshot - the graph to write\n * @param format - a format name where `canExport` is true\n * @param options - sanitizeIds, onMixedDirection and the format's own options\n * @returns the encoded file\n */\n exportGraphToBytes(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n ): Promise<Uint8Array> {\n return collectBytes(this.exportGraph(snapshot, format, options));\n }\n\n /**\n * Write a snapshot in a format as a Blob typed with the format's first MIME type; see the\n * top-level exportGraphToBlob().\n * @param snapshot - the graph to write\n * @param format - a format name where `canExport` is true\n * @param options - sanitizeIds, onMixedDirection and the format's own options\n * @returns the file as a Blob\n */\n async exportGraphToBlob(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n ): Promise<Blob> {\n const parts: Uint8Array[] = [];\n for await (const chunk of this.exportGraph(snapshot, format, options)) {\n parts.push(chunk);\n }\n const info = this.listFormats().find((f) => f.format === format);\n return new Blob(parts as BlobPart[], { type: info?.mimeTypes[0] ?? \"application/octet-stream\" });\n }\n\n /**\n * What exporting a snapshot in a format would lose, without writing anything.\n * @param snapshot - the snapshot\n * @param format - the format name\n * @param options - the exporter's common and format-specific options\n * @returns the loss notes, empty when the export is exact\n */\n checkExport(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n ): readonly LossNote[] {\n const styled = this.styled(snapshot, format, options);\n let notes: readonly LossNote[];\n if (styled === null) {\n notes = this.exporter(format).check(snapshot, options);\n } else if (styled.refusal === null) {\n // a property graph-io already reports as not written is reported once, whoever else notices\n const key = (n: LossNote): string =>\n `${n.code}\\u0000${n.style?.target ?? \"\"}\\u0000${n.style?.property ?? \"\"}`;\n const reported = new Set(styled.notes.filter((n) => n.style !== undefined).map(key));\n notes = [\n ...styled.exporter\n .check(styled.snapshot, styled.options)\n .filter(\n (n) =>\n n.style === undefined ||\n (!reported.has(key(n)) && !isKeptGraphtyProperty(n, styled.exporter)),\n ),\n ...styled.notes,\n ];\n } else {\n notes = [...styled.exporter.check(snapshot, styled.plain), styled.refusal];\n }\n const unknown = this.unknownOptions(options);\n if (unknown.length === 0) {\n return notes;\n }\n return Object.freeze([\n ...notes,\n ...unknown.map((name) =>\n Object.freeze({\n code: UNKNOWN_OPTION_CODE,\n message: unknownOptionText(name),\n column: null,\n count: null,\n }),\n ),\n ]);\n }\n\n /**\n * The option names no registered format and no load or save function takes (misspellings), or none while a\n * registered format does not list its options.\n * @param options - the caller's options\n * @returns the unknown names\n */\n private unknownOptions(options: object | null | undefined): string[] {\n if (options === null || options === undefined) {\n return [];\n }\n const known = new Set(FUNCTION_OPTIONS);\n for (const plugin of [...this.importerMap.values(), ...this.exporterMap.values()]) {\n if (plugin.options === undefined) {\n return [];\n }\n for (const name of plugin.options) {\n known.add(name);\n }\n }\n return Object.entries(options)\n .filter(([name, value]) => value !== undefined && !known.has(name))\n .map(([name]) => name);\n }\n\n /**\n * Browser only: write a graph in a format and have the browser save it as a file; see the\n * top-level downloadGraph(). Use this method on a registry from createRegistry() to download\n * without bundling every built-in format.\n * @param snapshot - the graph to write\n * @param format - a format name from listFormats() where `canExport` is true\n * @param options - the export options, plus `filename`\n * @returns resolves once the download has been handed to the browser\n */\n async downloadGraph(\n snapshot: GraphSnapshot,\n format: FormatName,\n options: DownloadGraphOptions | CommonExportOptions = {},\n ): Promise<void> {\n if (typeof document === \"undefined\") {\n throw new GraphFormatError(\n \"E_UNSUPPORTED\",\n \"downloadGraph() needs a browser document; use exportGraphToBytes() and write the bytes yourself\",\n );\n }\n const { filename, ...rest } = options as DownloadGraphOptions;\n const blob = await this.exportGraphToBlob(snapshot, format, rest);\n const extension = this.listFormats().find((f) => f.format === format)?.extensions[0] ?? `.${format}`;\n const href = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = href;\n anchor.download = filename ?? `graph${extension}`;\n anchor.click();\n // Safari cancels the download when the URL is revoked in the same task\n setTimeout(() => {\n URL.revokeObjectURL(href);\n }, 0);\n }\n\n /**\n * Every format this registry can read or write, in registration order; see the top-level\n * listFormats().\n * @returns one entry per format\n */\n listFormats(): readonly FormatInfo[] {\n return this.formats().map((format) => {\n const importer = this.importerMap.get(format);\n const exporter = this.exporterMap.get(format);\n return Object.freeze({\n format,\n extensions: importer?.extensions ?? exporter?.extensions ?? [],\n mimeTypes: importer?.mimeTypes ?? exporter?.mimeTypes ?? [],\n canImport: importer !== undefined,\n canExport: exporter !== undefined,\n capabilities: capabilitiesOf(exporter),\n });\n });\n }\n}\n\n/**\n * A new registry holding every built-in importer and exporter, in the order of GRAPH_FORMATS.\n * @returns a new registry\n * @category Formats and detection\n */\nexport function createRegistry(): FormatRegistry {\n const formats = new FormatRegistry()\n .registerImporter(jsonImporter)\n .registerExporter(jsonExporter)\n .registerImporter(graphmlImporter)\n .registerExporter(graphmlExporter)\n .registerImporter(gexfImporter)\n .registerExporter(gexfExporter)\n .registerImporter(csvImporter)\n .registerExporter(csvExporter)\n .registerImporter(gmlImporter)\n .registerExporter(gmlExporter)\n .registerImporter(dotImporter)\n .registerExporter(dotExporter)\n .registerImporter(pajekImporter)\n .registerExporter(pajekExporter)\n .registerImporter(neo4jImporter)\n .registerExporter(neo4jExporter)\n .registerImporter(xgmmlImporter)\n .registerExporter(xgmmlExporter)\n .registerImporter(cx2Importer)\n .registerExporter(cx2Exporter)\n .registerImporter(cxImporter)\n .registerExporter(cxExporter)\n .registerImporter(oboImporter)\n .registerExporter(oboExporter)\n .registerImporter(cysImporter)\n .registerExporter(cysExporter);\n for (const source of builtinSources()) {\n formats.registerSource(source);\n }\n return formats;\n}\n\n/**\n * The default registry: every built-in format.\n * @category Formats and detection\n */\nexport const registry: FormatRegistry = /* @__PURE__ */ createRegistry();\n\n/**\n * Read a graph from a string, bytes or a stream. The format is the one you name in `format`, else\n * it is detected from `filename`, `mimeType` and the first bytes; an input that matches no format\n * fails with E_UNKNOWN_FORMAT. From a file that holds several graphs it reads the one `graphIndex`\n * or `graphName` chooses, else the first, with a W_MULTIPLE_GRAPHS warning. For a File or Blob use\n * loadFromFile(), for a URL loadFromUrl().\n * @param input - the whole text, the bytes (a Uint8Array or a Node Buffer), a ReadableStream of\n * bytes, or an async iterable of text or byte chunks (a Node read stream)\n * @param options - the format, format hints, the options every importer takes and the format's own\n * options\n * @returns the graph (`snapshot`), the format it was read as, and the import report\n * @throws ImportError when the input could not be read; `err.issue?.code` says why\n * @throws GraphFormatError with code E_UNSUPPORTED for a `format` no importer is registered for, or\n * an option value that is not allowed (`err.details.option` names it)\n * @throws the signal's reason when `signal` aborts\n * @category Loading\n */\nexport function importGraph(\n input: ImportInput,\n options?: ImportGraphOptions | CommonImportOptions,\n): Promise<ImportGraphResult> {\n return registry.importGraph(input, options);\n}\n\n/**\n * Read every graph of a file that can hold several (DOT, GML, a Pajek project, a JSON Graph Format\n * or OBO Graphs document, CX, XGMML, a Cytoscape session). A format that holds one graph per file\n * gives one result. Options and errors are the same as importGraph()'s.\n * @param input - the text, bytes or stream to read\n * @param options - the same options as importGraph()\n * @returns one result per graph, in file order\n * @category Loading\n */\nexport function importAllGraphs(\n input: ImportInput,\n options?: ImportGraphOptions | CommonImportOptions,\n): Promise<ImportGraphResult[]> {\n return registry.importAllGraphs(input, options);\n}\n\n/**\n * List the graphs of a file without reading them: each one's `index`, `name`, and node and edge\n * counts when the file states them. Pass the index or name to importGraph() as `graphIndex` or\n * `graphName`. The counts come from the file and can differ from what an import reads, for example\n * when the import adds edges the listing does not count. JSON, CX, XGMML and Cytoscape sessions can\n * list their graphs; for DOT, GML and Pajek it returns null, and importAllGraphs() is the way to see\n * them.\n * @param input - the text, bytes or stream to read\n * @param options - the same options as importGraph()\n * @returns one listing per graph, in file order; null when the format cannot list its graphs\n * @category Loading\n */\nexport function listGraphs(\n input: ImportInput,\n options?: ImportGraphOptions | CommonImportOptions,\n): Promise<readonly GraphListing[] | null> {\n return registry.listGraphs(input, options);\n}\n\n/**\n * Write a graph in a format as a stream of UTF-8 byte chunks, for a graph too large to hold as one\n * file in memory. In Node, pipe it to a file with `pipeline(exportGraph(...), createWriteStream(path))`.\n * Options and errors are the same as exportGraphToBytes()'s.\n * @param snapshot - the graph to write\n * @param format - a format name from listFormats() where `canExport` is true\n * @param options - sanitizeIds, onMixedDirection and the format's own options\n * @returns the file's bytes, chunk by chunk\n * @category Saving\n */\nexport function exportGraph(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n): AsyncIterable<Uint8Array> {\n return registry.exportGraph(snapshot, format, options);\n}\n\n/**\n * Write a graph in a format and return the file as one string. A binary format (a Cytoscape\n * session) cannot be a string and fails with E_UNSUPPORTED; use exportGraphToBytes() for it. Options\n * and errors are the same as exportGraphToBytes()'s.\n * @param snapshot - the graph to write\n * @param format - a format name from listFormats() where `canExport` is true\n * @param options - sanitizeIds, onMixedDirection and the format's own options\n * @returns the whole file\n * @category Saving\n */\nexport async function exportGraphToString(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n): Promise<string> {\n return registry.exportGraphToString(snapshot, format, options);\n}\n\n/**\n * What saving a graph in a format would lose, without writing anything. Pass the same options you\n * will pass to the save. Each note has a stable `code`: \"E_\" means the save would throw, \"W_\" means\n * the file is written but that part does not read back the same. An empty array means the file\n * reads back as the same graph. Runs synchronously.\n * @param snapshot - the graph to check\n * @param format - a format name from listFormats() where `canExport` is true\n * @param options - the options you will save with\n * @returns the loss notes, empty when the save is exact\n * @throws GraphFormatError with code E_UNSUPPORTED when no exporter is registered for `format`, or\n * when an option value is not allowed (`err.details.option` names it)\n * @category Saving\n */\nexport function checkExport(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n): readonly LossNote[] {\n return registry.checkExport(snapshot, format, options);\n}\n\n/**\n * Fetch a graph file from a URL and load it. The file is streamed into the importer as it\n * downloads, so a large file is not held in memory twice. When you do not name a `format`, it is\n * worked out from the URL's file name, the response's Content-Type and the first bytes of the\n * file. Your own `filename` or `mimeType` option takes the place of the hint from the URL or the\n * response. Every other option goes to importGraph() unchanged, including format-specific ones\n * such as `delimiter` or `dialect`, and `graphIndex` / `graphName` for files that hold several\n * graphs. The result is the same as importGraph()'s. A successful load can still have skipped\n * elements; check `report.errorCount` and `report.warningCount`, or pass `errorLimit: 0` to make\n * the first error fatal. Works wherever fetch exists: browsers, Node 18 and later, Deno, Bun and\n * workers.\n * @param url - an absolute URL, or in a browser one relative to the page\n * @param options - import options, plus `request` for fetch\n * @returns the graph, the format it was read as, and the import report\n * @throws ImportError when the file could not be loaded; `err.issue?.code` is \"E_FETCH\" for a\n * network failure, a CORS refusal or a status outside 200-299 (`err.details.url`,\n * `err.details.status` -- null for a network failure -- and `err.details.cause`, fetch's own\n * error), \"E_UNKNOWN_FORMAT\" when no format recognizes the file (pass `format`), or the code of\n * the parse error\n * @throws GraphFormatError with code E_UNSUPPORTED when `format` names no registered importer\n * @throws the signal's reason when `signal` aborts\n * @example\n * ```ts\n * import { GraphFormatError, loadFromUrl } from \"@graphty/graph-io\";\n *\n * try {\n * const { snapshot, format } = await loadFromUrl(\"https://example.com/data/karate.gml\");\n * console.log(`${format}: ${snapshot.nodeCount} nodes, ${snapshot.edgeCount} edges`);\n * } catch (err) {\n * if (err instanceof GraphFormatError) {\n * console.error(err.message);\n * } else {\n * throw err;\n * }\n * }\n * ```\n * @category Loading\n */\nexport function loadFromUrl(\n url: string | URL,\n options?: LoadFromUrlOptions | CommonImportOptions,\n): Promise<ImportGraphResult> {\n return registry.loadFromUrl(url, options);\n}\n\n/**\n * Load a graph from a File or Blob: a file the user picked in an `<input type=\"file\">`, a file\n * dropped on the page, a Blob you built, or in Node a Blob from `fs.openAsBlob(path)`. The content\n * is streamed into the importer. A File's `name` and the Blob's `type` are used as format hints\n * unless you pass `filename` or `mimeType` yourself. Options, result and errors are the same as\n * loadFromUrl()'s, without E_FETCH.\n * @param file - the File or Blob to read\n * @param options - the same options as importGraph()\n * @returns the graph, the format it was read as, and the import report\n * @throws ImportError when the file could not be loaded (`err.issue?.code` E_UNKNOWN_FORMAT or a parse error)\n * @throws GraphFormatError with code E_UNSUPPORTED when `format` names no registered importer\n * @throws the signal's reason when `signal` aborts\n * @example\n * ```ts\n * input.addEventListener(\"change\", async () => {\n * const file = input.files?.[0];\n * if (file) {\n * const { snapshot, report } = await loadFromFile(file);\n * console.log(`${snapshot.nodeCount} nodes, ${report.errorCount} skipped`);\n * }\n * });\n * ```\n * @category Loading\n */\nexport function loadFromFile(\n file: Blob,\n options?: ImportGraphOptions | CommonImportOptions,\n): Promise<ImportGraphResult> {\n return registry.loadFromFile(file, options);\n}\n\n/**\n * Write a graph in a format and return the whole file as UTF-8 bytes, ready for fs.writeFile, a\n * fetch body or a zip entry. Prefer this over exportGraphToString() when the result goes to a file\n * or the network. To stream a very large graph, use exportGraph(). To find out beforehand what the\n * file will not keep, call checkExport() with the same format and the same options object: every\n * \"E_\" note it returns makes this call throw, and every \"W_\" note describes a loss this call\n * accepts. Most \"E_\" notes go away with `sanitizeIds: \"mangle\"` (rewrite ids the format cannot\n * hold) or `onMixedDirection: \"directed\"` / `\"undirected\"`. The format's own options (the CSV\n * `table` and `dialect`, the GEXF `version`, ...) go in the same object.\n * @param snapshot - the graph to write\n * @param format - a format name from listFormats() where `canExport` is true\n * @param options - sanitizeIds, onMixedDirection and the format's own options\n * @returns the encoded file\n * @throws GraphFormatError with code E_UNSUPPORTED when no exporter is registered for `format`\n * @throws GraphFormatError when the graph cannot be written in this format under these options\n * (checkExport() returns an \"E_\" note for the same call). The thrown code names the kind of\n * failure rather than the note: E_INVALID_ID for ids (the E_ID_CHARSET and E_ID_TEXT_COLLISION\n * notes), E_DIRECTED for direction (E_MIXED_DIRECTION), and E_COLUMN_TYPE or E_UNSUPPORTED for a\n * value the format cannot write; each note's entry on the codes page says which\n * @throws GraphFormatError with code E_UNSUPPORTED for an option value that is not allowed\n * (`err.details.option` names it)\n * @example\n * ```ts\n * import { writeFile } from \"node:fs/promises\";\n *\n * await writeFile(\"out.gexf\", await exportGraphToBytes(snapshot, \"gexf\"));\n * ```\n * @category Saving\n */\nexport function exportGraphToBytes(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n): Promise<Uint8Array> {\n return registry.exportGraphToBytes(snapshot, format, options);\n}\n\n/**\n * Write a graph in a format and return it as a Blob, for uploading with fetch or FormData or for\n * offering as a download. The Blob's `type` is the first entry of the format's `mimeTypes` in\n * listFormats(), or application/octet-stream when the format lists none. The exporter's chunks\n * are kept as they are and never joined into one string. Options and errors are the same as\n * exportGraphToBytes().\n * @param snapshot - the graph to write\n * @param format - a format name from listFormats() where `canExport` is true\n * @param options - sanitizeIds, onMixedDirection and the format's own options\n * @returns the file as a Blob\n * @throws the same errors as exportGraphToBytes()\n * @example\n * ```ts\n * const body = new FormData();\n * body.append(\"file\", await exportGraphToBlob(snapshot, \"graphml\"), \"graph.graphml\");\n * await fetch(\"/api/graphs\", { method: \"POST\", body });\n * ```\n * @category Saving\n */\nexport function exportGraphToBlob(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n): Promise<Blob> {\n return registry.exportGraphToBlob(snapshot, format, options);\n}\n\n/**\n * Browser only: write a graph in a format and have the browser save it as a file, the same as\n * clicking a download link. Call it from a click handler; awaiting other work first is fine. The\n * promise resolves once the file has been handed to the browser. There is no way to learn\n * whether the user then canceled the save. Calling it where there is no `document` (Node, a\n * worker) throws instead of silently doing nothing; importing it is safe everywhere. Formats you\n * registered with `registry.registerExporter()` can be downloaded too.\n * @param snapshot - the graph to write\n * @param format - a format name from listFormats() where `canExport` is true\n * @param options - the export options, plus `filename`\n * @returns resolves once the download has been handed to the browser\n * @throws GraphFormatError with code E_UNSUPPORTED when called without a DOM `document`\n * @throws the same errors as exportGraphToBytes()\n * @example\n * ```ts\n * saveButton.addEventListener(\"click\", () => {\n * void downloadGraph(snapshot, \"graphml\", { filename: \"network.graphml\" });\n * });\n * ```\n * @category Saving\n */\nexport async function downloadGraph(\n snapshot: GraphSnapshot,\n format: FormatName,\n options: DownloadGraphOptions | CommonExportOptions = {},\n): Promise<void> {\n return registry.downloadGraph(snapshot, format, options);\n}\n\n/**\n * Every format the default registry can read or write, including any you registered yourself:\n * the built-in formats in the order of GRAPH_FORMATS (the order format detection prefers them),\n * then yours in registration order. Use it to fill a \"Save as\" menu (the entries with\n * `canExport`), a file input's `accept` attribute (the `extensions` of the entries with\n * `canImport`), or to pick the output format from a file name.\n * @returns one entry per format\n * @example\n * ```ts\n * input.accept = listFormats().filter((f) => f.canImport).flatMap((f) => f.extensions).join(\",\");\n * const target = listFormats().find((f) => f.canExport && f.extensions.includes(extensionOf(path) ?? \"\"));\n * ```\n * @category Formats and detection\n */\nexport function listFormats(): readonly FormatInfo[] {\n return registry.listFormats();\n}\n\n/**\n * Detect a file's format without reading it, from what you know about it: a `filename` (only the\n * extension counts), a `mimeType`, and `head`, the file's first bytes or characters (up to\n * SNIFF_HEAD_BYTES; pass `bytes.subarray(0, SNIFF_HEAD_BYTES)`). It uses every format of the default\n * registry, including the ones you registered. For every candidate, best first, call\n * `registry.sniffAll(hints)`.\n * @param hints - `{ filename, mimeType, head }`, any of them\n * @returns the best candidate (`format`, `confidence` and what matched), or null when no format\n * claims the input\n * @example\n * ```ts\n * sniff({ filename: \"graph.xml\", head: \"<?xml version=\\\"1.0\\\"?><gexf\" })?.format; // \"gexf\"\n * ```\n * @category Formats and detection\n */\nexport function sniff(hints: SniffHints): SniffResult | null {\n return registry.sniff(hints);\n}\n\n/**\n * Abort a loadFromUrl() whose fetch failed with an E_FETCH ImportError.\n * @param options - the import options (for the format name on the report)\n * @param url - the URL\n * @param message - the message\n * @param status - the HTTP status, or null for a network failure\n * @param cause - fetch's own error, or null\n * @returns never; always throws\n */\nfunction fetchFailed(\n options: ImportGraphOptions,\n url: string | URL,\n message: string,\n status: number | null,\n cause: unknown,\n): never {\n const format = options.format === undefined || options.format === \"auto\" ? \"unknown\" : options.format;\n return new ImportReportBuilder(format, 0).fail(FETCH_CODE, message, undefined, { url: String(url), status, cause });\n}\n\n/**\n * The error for an input refused by the format the caller named before any element was read: the\n * parser's message (\"line 1: text outside the root element\") prefixed with the file and the format,\n * since the likely cause is a file of another kind, not a damaged one.\n * @param err - what the importer threw\n * @param format - the format named in `format`\n * @param filename - the file name hint, if any\n * @returns the error to throw\n */\nfunction notReadableAs(err: unknown, format: string, filename: string | null | undefined): unknown {\n if (\n !(err instanceof ImportError) ||\n err.issue?.category !== \"parse-error\" ||\n err.report.errorCount > 1 ||\n err.report.counts.nodes + err.report.counts.edges > 0\n ) {\n return err;\n }\n const what = filename === undefined || filename === null ? \"the input\" : JSON.stringify(filename);\n return new ImportError(`${what} could not be read as ${format}: ${err.message}`, err.report, err.details);\n}\n\n/**\n * Why fetch() rejected, in words that point at the fix: a relative URL with no page to resolve it\n * against (Node), a file: URL fetch() does not read, or a network error, which in a browser\n * includes a CORS refusal.\n * @param url - the URL as given\n * @param err - what fetch() threw\n * @returns the reason\n */\nfunction fetchErrorText(url: string | URL, err: unknown): string {\n let absolute: URL | null = null;\n try {\n absolute = new URL(url);\n } catch {\n // relative: resolvable only against a page's location\n }\n if (absolute === null && (globalThis as { location?: unknown }).location === undefined) {\n return \"a relative URL needs a web page to resolve against; outside a browser pass an absolute http(s) URL, or read a local file with loadFromFile() or importGraph()\";\n }\n if (absolute?.protocol === \"file:\") {\n return \"fetch() cannot read file: URLs here; read a local file with loadFromFile() or importGraph()\";\n }\n const cause = (err as { cause?: { message?: unknown } } | null)?.cause?.message;\n const detail = typeof cause === \"string\" && cause !== \"\" ? ` (${cause})` : \"\";\n return `the server could not be reached, or (in a browser) it does not allow this page to read the file (CORS)${detail}`;\n}\n\n/**\n * The last path segment of a URL, as a format hint.\n * @param url - the URL, absolute or relative\n * @returns the file name, or null when the path ends in \"/\"\n */\nfunction urlFilename(url: string | URL): string | null {\n const path = new URL(url, \"http://localhost/\").pathname;\n const name = path.slice(path.lastIndexOf(\"/\") + 1);\n return name === \"\" ? null : name;\n}\n\n/**\n * The options handed to the importer: everything but the registry's own keys.\n * @param options - the importGraph options\n * @returns the importer's options\n */\nfunction importerOptions(options: ImportGraphOptions): CommonImportOptions {\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(options)) {\n if (!REGISTRY_KEYS.has(key)) {\n out[key] = value;\n }\n }\n return out;\n}\n\n/** The importer chosen for an input, and the input to hand it. */\ninterface ChosenImporter {\n /** The importer. */\n readonly importer: GraphImporter;\n /** The sniff that chose it, or null when the caller named the format. */\n readonly sniff: SniffResult | null;\n /** The input to read: the original, or a replaying iterable for a peeked stream. */\n readonly source: ImportInput;\n /** The peeked head of a sniffed input, or null. */\n readonly peeked: PeekedInput | null;\n /** W_SNIFF_FAILED warnings for the import report, one per importer whose sniff() threw. */\n readonly warnings: readonly ImportIssue[];\n}\n\n/**\n * A fresh builder seeded from the common options, `directed: true` as a placeholder the importer\n * overrides from the file, that stops the import when its attributes get too sparse.\n * @param options - the importGraph options\n * @param format - the format being read\n * @returns the builder\n */\nfunction seededBuilder(options: ImportGraphOptions, format: string): GraphBuilder {\n const maxEmptyCells = maxEmptyCellsOption(options.maxEmptyCells);\n try {\n return newBuilder(options, format, maxEmptyCells);\n } catch (err) {\n // the builder names a bad value by its field; report it as the option the caller passed\n if (err instanceof GraphFormatError && err.code === \"E_UNSUPPORTED\" && typeof err.details.field === \"string\") {\n const option = err.details.field;\n throw new GraphFormatError(\n \"E_UNSUPPORTED\",\n `option ${option}: ${JSON.stringify(err.details.found)} is not one of the values it takes`,\n { option, found: err.details.found },\n );\n }\n throw err;\n }\n}\n\n/**\n * The builder of seededBuilder(), before its option errors are reworded.\n * @param options - the importGraph options\n * @param format - the format being read\n * @param maxEmptyCells - the empty-cell budget\n * @returns the builder\n */\nfunction newBuilder(options: ImportGraphOptions, format: string, maxEmptyCells: number): GraphBuilder {\n return new CellBudgetBuilder(\n {\n weightDtype: options.weightDtype ?? \"f64\",\n ...options.builder,\n directed: true,\n addMissingNodes: options.addMissingNodes ?? true,\n duplicateEdges: options.duplicateEdges ?? \"keep\",\n selfLoops: options.selfLoops ?? \"keep\",\n },\n format,\n maxEmptyCells,\n );\n}\n\n/**\n * Name the graph an importAllGraphs() failure belongs to: the report is that graph's own, so the\n * message is prefixed with its index and `details.graphIndex` set, for every graph including the\n * first. Anything other than an ImportError raised while a graph was being read passes unchanged.\n * @param err - the error thrown while reading or freezing a graph\n * @param index - the index of that graph, -1 before the first graph began\n * @returns the error to throw\n */\nfunction inGraph(err: unknown, index: number): unknown {\n if (!(err instanceof ImportError) || index < 0) {\n return err;\n }\n return new ImportError(`graph ${index}: ${err.message}`, err.report, { ...err.details, graphIndex: index });\n}\n\n/**\n * Freeze an imported builder into an importGraph result.\n * @param chosen - the importer and its sniff\n * @param builder - the filled builder\n * @param report - the importer's report\n * @param options - the importGraph options\n * @returns the frozen result\n */\nfunction result(\n chosen: ChosenImporter,\n builder: GraphBuilder,\n report: ImportReport,\n options: ImportGraphOptions,\n): ImportGraphResult {\n let frozen: ReturnType<GraphBuilder[\"freezeWithReport\"]>;\n try {\n frozen = builder.freezeWithReport(options.freeze);\n } catch (err) {\n throw freezeFailure(err, report);\n }\n const { warnings } = chosen;\n const wanted = options.styles;\n let styles: ExtractedStyles | null | undefined;\n if (wanted !== undefined && wanted !== false) {\n styles = extractStyles(chosen.importer, frozen.snapshot, report, {\n signal: options.signal,\n toolDefaults: typeof wanted === \"object\" ? wanted.toolDefaults : undefined,\n });\n }\n const read =\n styles !== undefined && chosen.importer.styles !== undefined ? withoutStylesNotImported(report) : report;\n const result = {\n format: chosen.importer.format,\n sniff: chosen.sniff,\n snapshot: frozen.snapshot,\n report: withFreezeWarnings(\n weightNotFound(\n warnings.length === 0\n ? read\n : Object.freeze({\n ...read,\n issues: Object.freeze([...warnings, ...read.issues]),\n warningCount: read.warningCount + warnings.length,\n }),\n frozen.snapshot,\n options.weightFrom,\n ),\n frozen.report,\n ),\n };\n if (styles !== undefined) {\n Object.assign(result, { styles });\n }\n // not enumerable: it holds one entry per edge, and console.log(result) should show the graph, not that\n Object.defineProperty(result, \"freeze\", { value: frozen.report, enumerable: false });\n return Object.freeze(result as ImportGraphResult);\n}\n\n/**\n * A report without its W_STYLES_NOT_IMPORTED warnings: the importer read the styles it would have named.\n * @param report - the importer's report\n * @returns the report, a copy only when it held such a warning\n */\nfunction withoutStylesNotImported(report: ImportReport): ImportReport {\n const issues = report.issues.filter((i) => i.code !== STYLES_NOT_IMPORTED_CODE);\n if (issues.length === report.issues.length) {\n return report;\n }\n return Object.freeze({\n ...report,\n issues: Object.freeze(issues),\n warningCount: report.warningCount - (report.issues.length - issues.length),\n });\n}\n\n/** An export with styles, worked out by FormatRegistry.styled(). */\ninterface StyledExport {\n /** The exporter. */\n readonly exporter: GraphExporter;\n /** The snapshot to hand it. */\n readonly snapshot: GraphSnapshot;\n /** The options to hand it: the caller's, with `styles` replaced by the exporter's input or left out. */\n readonly options: ExportGraphOptions;\n /** The caller's options without `styles`. */\n readonly plain: ExportGraphOptions;\n /** The style losses. */\n readonly notes: readonly LossNote[];\n /** E_STYLES_MISMATCH, or null. */\n readonly refusal: LossNote | null;\n}\n\n/**\n * The error an export refused for its styles throws.\n * @param note - the refusal note\n * @returns the error\n */\nfunction refusalError(note: LossNote): GraphFormatError {\n return new GraphFormatError(\"E_UNSUPPORTED\", note.message, { code: note.code });\n}\n\n/**\n * Chunks that fail on the first read, before any byte: an export refused for its styles.\n * @param note - the refusal note\n * @returns chunks whose first read rejects\n */\nfunction refuse(note: LossNote): AsyncIterable<Uint8Array> {\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(refusalError(note)) }),\n };\n}\n\n/**\n * The capabilities listFormats() reports for an exporter: its table plus, when it writes styles, their capabilities.\n * @param exporter - the exporter, or undefined\n * @returns the capabilities, or null\n */\nfunction capabilitiesOf(exporter: GraphExporter | undefined): ExportCapabilities | null {\n if (exporter === undefined) {\n return null;\n }\n if (exporter.styles === undefined) {\n return exporter.capabilities;\n }\n return Object.freeze({ ...exporter.capabilities, styles: exporter.styles.capabilities });\n}\n\n/**\n * The message of a W_UNKNOWN_OPTION warning or note.\n * @param name - the option name\n * @returns the message\n */\nfunction unknownOptionText(name: string): string {\n return `option ${JSON.stringify(name)} is not an option of any format or of the load and save functions, so it has no effect; check its spelling`;\n}\n\n/**\n * The import report with one W_WEIGHT_NOT_FOUND warning when the caller's `weightFrom` named an attribute that gave\n * no edge a weight, so a name that misses (a shared options object read against GML's `value`) is not silent. A\n * format that does not read `weightFrom` already reported it as W_OPTION_IGNORED.\n * @param report - the import's report\n * @param snapshot - the graph read\n * @param weightFrom - the caller's option\n * @returns the report, with the warning added when it applies\n */\nfunction weightNotFound(report: ImportReport, snapshot: GraphSnapshot, weightFrom: unknown): ImportReport {\n if (\n typeof weightFrom !== \"string\" ||\n snapshot.edgeCount === 0 ||\n snapshot.edgeList().weights !== null ||\n report.issues.some((i) => i.code === OPTION_IGNORED_CODE && i.element === \"weightFrom\")\n ) {\n return report;\n }\n const issue: ImportIssue = Object.freeze({\n category: \"missing-value\",\n severity: \"warning\",\n code: WEIGHT_NOT_FOUND_CODE,\n message: `weightFrom: ${JSON.stringify(weightFrom)} names no attribute an edge has a value for, so the graph has no weights`,\n line: null,\n element: \"weightFrom\",\n });\n return Object.freeze({\n ...report,\n issues: Object.freeze([...report.issues, issue]),\n warningCount: report.warningCount + 1,\n });\n}\n\n/**\n * The import report with what the builder's policies changed while the graph was built: one\n * W_EDGES_MERGED warning when `duplicateEdges` merged parallel edges (whatever told them apart, a\n * relation or a label, is lost) and one W_SELF_LOOPS_DROPPED warning when `selfLoops: \"drop\"`\n * removed self-loops, so nothing the caller's options removed goes unreported.\n * @param report - the import's report\n * @param freeze - the freeze report\n * @returns the report, with the warnings added\n */\nfunction withFreezeWarnings(report: ImportReport, freeze: FreezeReport): ImportReport {\n const added: ImportIssue[] = [];\n const warn = (category: IssueCategory, code: string, message: string): void => {\n added.push(Object.freeze({ category, severity: \"warning\" as const, code, message, line: null, element: null }));\n };\n if (freeze.mergedEdges > 0) {\n warn(\n \"merged\",\n EDGES_MERGED_CODE,\n `${freeze.mergedEdges} parallel edge${plural(freeze.mergedEdges)} ${agree(freeze.mergedEdges, \"was\", \"were\")} merged into one edge per pair by the duplicateEdges policy; whatever told them apart (a relation, a label) is lost`,\n );\n }\n if (freeze.droppedSelfLoops > 0) {\n warn(\n \"validation-error\",\n SELF_LOOPS_DROPPED_CODE,\n `${freeze.droppedSelfLoops} self-loop${plural(freeze.droppedSelfLoops)} ${agree(freeze.droppedSelfLoops, \"was\", \"were\")} removed by selfLoops: \"drop\"`,\n );\n }\n if (added.length === 0) {\n return report;\n }\n return Object.freeze({\n ...report,\n issues: Object.freeze([...report.issues, ...added]),\n warningCount: report.warningCount + added.length,\n });\n}\n\n/**\n * The ImportError of a freeze the builder refused (a `duplicateEdges: \"error\"` or `selfLoops:\n * \"error\"` policy meeting a duplicate edge or a self-loop the file holds): the builder's code\n * recorded as an error issue on the import's report, so the caller gets the report and the file's\n * defect rather than a bare GraphFormatError.\n * @param err - what freezeWithReport() threw\n * @param report - the import's report\n * @returns the error to throw (anything that is not a GraphFormatError, unchanged)\n */\nfunction freezeFailure(err: unknown, report: ImportReport): unknown {\n if (!(err instanceof GraphFormatError) || err instanceof ImportError) {\n return err;\n }\n const issue = Object.freeze({\n category: \"validation-error\" as const,\n severity: \"error\" as const,\n code: err.code,\n message: err.message,\n line: null,\n element: null,\n });\n const failed: ImportReport = Object.freeze({\n ...report,\n issues: Object.freeze([...report.issues, issue]),\n errorCount: report.errorCount + 1,\n });\n return new ImportError(`the graph cannot be frozen: ${err.message}`, failed, { code: err.code, ...err.details });\n}\n\n/**\n * The E_UNSUPPORTED error of a format name nothing is registered under.\n * @param kind - importer or exporter\n * @param format - the requested name\n * @param known - the registered names\n * @returns the error\n */\nfunction unknownFormat(kind: \"importer\" | \"exporter\", format: string, known: Iterable<string>): GraphFormatError {\n const supported = [...known];\n return new GraphFormatError(\n \"E_UNSUPPORTED\",\n `no ${kind} is registered for format ${JSON.stringify(format)}; known: ${supported.join(\", \")}`,\n { option: \"format\", found: format, supported },\n );\n}\n\n/**\n * The hints of an import, for the unknown-format message.\n * @param options - the importGraph options\n * @returns \" (filename ..., MIME type ...)\" or an empty string\n */\nfunction describeHints(options: ImportGraphOptions): string {\n const parts: string[] = [];\n if (typeof options.filename === \"string\" && options.filename.length > 0) {\n parts.push(`filename ${JSON.stringify(options.filename)}`);\n }\n if (typeof options.mimeType === \"string\" && options.mimeType.length > 0) {\n parts.push(`MIME type ${JSON.stringify(options.mimeType)}`);\n }\n return parts.length === 0 ? \"\" : ` (${parts.join(\", \")})`;\n}\n\n/** A head read from an input, and the input to hand the importer (the same bytes, replayed for a stream). */\ninterface PeekedInput {\n /** The first bytes (or, for a text input, characters) of the content. */\n readonly head: Uint8Array | string;\n /** The input to read: the original for in-memory input, a replaying iterable for a stream. */\n readonly input: ImportInput;\n /**\n * Close the source when the importer never iterated the replaying input (it threw first, an\n * abort for instance): a stream's reader is canceled and released, an async generator finalised.\n * @returns when the source is closed\n */\n close(): Promise<void>;\n}\n\n/**\n * The first `bytes` of an input without consuming it: in-memory input is sliced; a stream or an\n * async iterable is read until enough is buffered and then replayed (the buffered chunks first,\n * the rest as it arrives) through a new async iterable that cancels the source when the importer\n * stops early.\n * @param input - the input\n * @param bytes - how much to peek\n * @param signal - the cancellation signal, or null\n * @returns the head and the input to read\n */\nasync function peekHead(input: ImportInput, bytes: number, signal: AbortSignal | null): Promise<PeekedInput> {\n if (typeof input === \"string\") {\n return { head: input.slice(0, bytes), input, close: (): Promise<void> => Promise.resolve() };\n }\n if (input instanceof Uint8Array) {\n return { head: input.subarray(0, bytes), input, close: (): Promise<void> => Promise.resolve() };\n }\n throwIfAborted(signal);\n const source: AsyncIterator<string | Uint8Array> =\n typeof (input as { getReader?: unknown }).getReader === \"function\"\n ? readerIterator(input as ReadableStream<Uint8Array>, signal)\n : (input as AsyncIterable<string | Uint8Array>)[Symbol.asyncIterator]();\n const buffered: (string | Uint8Array)[] = [];\n let size = 0;\n let finished = false;\n while (size < bytes) {\n if (signal?.aborted) {\n await source.return?.();\n throwIfAborted(signal);\n }\n const next = await source.next();\n if (next.done === true) {\n finished = true;\n break;\n }\n buffered.push(next.value);\n size += typeof next.value === \"string\" ? next.value.length : next.value.byteLength;\n }\n if (!finished && signal?.aborted) {\n // an abort that landed on the read completing the head: close the source before rethrowing\n await source.return?.();\n throwIfAborted(signal);\n }\n const replayed = replay(buffered, source, finished);\n return { head: joinHead(buffered, bytes), input: replayed, close: (): Promise<void> => replayed.close() };\n}\n\n/**\n * The head text or bytes of the buffered chunks: bytes when every chunk is bytes, text otherwise\n * (byte chunks decoded leniently; the importer decodes the real input strictly).\n * @param chunks - the buffered chunks\n * @param bytes - the head size\n * @returns the head\n */\nfunction joinHead(chunks: readonly (string | Uint8Array)[], bytes: number): Uint8Array | string {\n if (chunks.every((c) => c instanceof Uint8Array)) {\n const total = Math.min(\n bytes,\n chunks.reduce((sum, c) => sum + c.byteLength, 0),\n );\n const head = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n if (offset >= total) {\n break;\n }\n const part = chunk.subarray(0, Math.min(chunk.byteLength, total - offset));\n head.set(part, offset);\n offset += part.byteLength;\n }\n return head;\n }\n const decoder = new TextDecoder(\"utf-8\", { fatal: false });\n let text = \"\";\n for (const chunk of chunks) {\n text += typeof chunk === \"string\" ? chunk : decoder.decode(chunk, { stream: true });\n if (text.length >= bytes) {\n break;\n }\n }\n return text.slice(0, bytes);\n}\n\n/**\n * An async iterable that yields the buffered chunks, then the rest of the source; the source is\n * closed when the consumer stops early.\n * @param buffered - the chunks already read\n * @param source - the iterator positioned after them\n * @param finished - whether the source is already exhausted\n * @returns the replaying iterable\n */\nfunction replay(\n buffered: readonly (string | Uint8Array)[],\n source: AsyncIterator<string | Uint8Array>,\n finished: boolean,\n): AsyncIterable<string | Uint8Array> & { close(): Promise<void> } {\n let exhausted = finished;\n const close = async (): Promise<void> => {\n if (!exhausted) {\n exhausted = true;\n await source.return?.();\n }\n };\n return {\n close,\n [Symbol.asyncIterator](): AsyncIterator<string | Uint8Array> {\n let position = 0;\n return {\n async next(): Promise<IteratorResult<string | Uint8Array>> {\n if (position < buffered.length) {\n return { done: false, value: buffered[position++] };\n }\n if (exhausted) {\n return { done: true, value: undefined };\n }\n const next = await source.next();\n if (next.done === true) {\n exhausted = true;\n return { done: true, value: undefined };\n }\n return next;\n },\n async return(): Promise<IteratorResult<string | Uint8Array>> {\n await close();\n return { done: true, value: undefined };\n },\n };\n },\n };\n}\n\n/**\n * An async iterator over a ReadableStream's chunks that cancels the stream (with the signal's\n * reason) when closed early or when the signal fires during a read, and releases the reader when\n * the stream ends or errors.\n * @param stream - the stream\n * @param signal - the cancellation signal, or null\n * @returns the iterator\n */\nfunction readerIterator(stream: ReadableStream<Uint8Array>, signal: AbortSignal | null): AsyncIterator<Uint8Array> {\n const reader = lockReader(stream);\n let done = false;\n return {\n async next(): Promise<IteratorResult<Uint8Array>> {\n if (done) {\n return { done: true, value: undefined };\n }\n let result: ReadableStreamReadResult<Uint8Array>;\n try {\n result = await abortable(reader.read(), signal);\n } catch (err) {\n done = true;\n await reader.cancel(signal?.reason).catch(() => undefined);\n reader.releaseLock();\n throw err;\n }\n if (result.done) {\n done = true;\n reader.releaseLock();\n return { done: true, value: undefined };\n }\n return { done: false, value: result.value };\n },\n async return(): Promise<IteratorResult<Uint8Array>> {\n if (!done) {\n done = true;\n await reader.cancel(signal?.reason).catch(() => undefined);\n reader.releaseLock();\n }\n return { done: true, value: undefined };\n },\n };\n}\n\n// ============================================================ network sources (experimental)\n\n/**\n * Load a graph from a network source: a built-in one by id (\"ndex\", \"neo4j\", \"openalex\", ...),\n * one you registered with registerSource(), or a source object. The source fetches through a\n * guarded fetch that sends the credential only to the endpoint's origin, never over plain http\n * (except to this machine), never across a redirect, and retries what is safe to retry. Every\n * failure is an ImportError whose `issue.code` is one of SOURCE_ISSUE and whose `issue.params`\n * holds its values. A capped load warns W_SOURCE_LIMIT and gives `report.source.next`, which you\n * pass as `cursor` to continue. `result.format` is \"source:<id>\", or the format a file source\n * was read as. Experimental.\n * @param source - the source id\n * @param params - its params, typed by SourceParamsMap\n * @param options - endpoint, credential, cursor, caps, retries and the import options\n * @returns the graph, the format and the report\n * @example\n * ```ts\n * const { snapshot } = await loadFromSource(\"people\", { team: \"core\" }, { endpoint: \"https://example.com\" });\n * ```\n * @category Network sources\n */\nexport function loadFromSource<K extends keyof SourceParamsMap>(\n source: K,\n params: SourceParamsMap[K],\n options?: LoadFromSourceOptions,\n): Promise<ImportGraphResult>;\n/**\n * Load a graph from a network source by id or as an object. Experimental.\n * @param source - the source id or the source\n * @param params - its params\n * @param options - endpoint, credential, cursor, caps, retries and the import options\n * @returns the graph, the format and the report\n * @category Network sources\n */\nexport function loadFromSource<P>(\n source: string | GraphSource<P>,\n params: P,\n options?: LoadFromSourceOptions,\n): Promise<ImportGraphResult>;\n/**\n * The implementation of both loadFromSource() signatures.\n * @param source - the source id or the source\n * @param params - its params\n * @param options - the options\n * @returns the graph, the format and the report\n */\nexport function loadFromSource(\n source: string | GraphSource<never>,\n params: unknown,\n options?: LoadFromSourceOptions,\n): Promise<ImportGraphResult> {\n return registry.loadFromSource(source, params as Readonly<Record<string, unknown>>, options);\n}\n\n/**\n * Load from a network source into a sink you own (a GraphBuilder you keep filling). Experimental.\n * @param source - the source id or the source\n * @param params - its params\n * @param sink - where to write\n * @param options - the options of loadFromSource()\n * @returns the report\n * @category Network sources\n */\nexport function importFromSource<P>(\n source: string | GraphSource<P>,\n params: P,\n sink: GraphSink,\n options?: LoadFromSourceOptions,\n): Promise<ImportReport> {\n return registry.importFromSource(source, params as Readonly<Record<string, unknown>>, sink, options);\n}\n\n/**\n * Fetch the neighborhood of some nodes from a source that can expand: a graph of only what was\n * fetched (the seeds, their neighbors and the edges between them), to merge into the graph you\n * hold. A source without `expand` rejects with E_SOURCE_UNSUPPORTED. Experimental.\n * @param source - the source id or the source\n * @param request - the params, seeds, depth, direction and limit\n * @param options - the options of loadFromSource()\n * @returns the fetched part, the format and the report\n * @category Network sources\n */\nexport function expandFromSource<P>(\n source: string | GraphSource<P>,\n request: ExpandRequest<P>,\n options?: LoadFromSourceOptions,\n): Promise<ImportGraphResult> {\n return registry.expandFromSource(source, request as ExpandRequest<Readonly<Record<string, unknown>>>, options);\n}\n\n/**\n * Check a source's params and credential without loading the graph. Experimental.\n * @param source - the source id or the source\n * @param params - its params\n * @param options - the options of loadFromSource()\n * @returns what the service said\n * @category Network sources\n */\nexport function probeSource<P>(\n source: string | GraphSource<P>,\n params: P,\n options?: LoadFromSourceOptions,\n): Promise<SourceProbe> {\n return registry.probeSource(source, params as Readonly<Record<string, unknown>>, options);\n}\n\n/**\n * Search what a source holds (NDEx networks, ...). Experimental.\n * @param source - the source id or the source\n * @param query - params narrowing the search, the search text, cursor and page size\n * @param options - the options of loadFromSource()\n * @returns one page of results\n * @category Network sources\n */\nexport function listFromSource<P>(\n source: string | GraphSource<P>,\n query: SourceListQuery<P>,\n options?: LoadFromSourceOptions,\n): Promise<SourceListing> {\n return registry.listFromSource(source, query, options);\n}\n\n/**\n * Tell whether data loaded from a source earlier changed. Experimental.\n * @param source - the source id or the source\n * @param params - the params it was loaded with\n * @param seen - the validators recorded then (`report.source.validators`)\n * @param options - the options of loadFromSource()\n * @returns current, changed or unverifiable\n * @category Network sources\n */\nexport function validateSource<P>(\n source: string | GraphSource<P>,\n params: P,\n seen: SourceValidators,\n options?: LoadFromSourceOptions,\n): Promise<SourceFreshness> {\n return registry.validateSource(source, params as Readonly<Record<string, unknown>>, seen, options);\n}\n\n/**\n * Register a network source in the default registry, so loadFromSource() and graphty-element\n * find it by id. Throws an ImportError with E_SOURCE_INVALID for a malformed source or an id\n * already taken. Experimental.\n * @param source - the source, or a lazy source that loads its code on first use\n * @category Network sources\n */\nexport function registerSource<P>(source: GraphSource<P> | LazySource): void {\n registry.registerSource(source);\n}\n\n/**\n * Every source in the default registry with its descriptor (what a form asks for), loading no\n * source code. Experimental.\n * @returns one entry per source: id, descriptor, whether its code is loaded\n * @category Network sources\n */\nexport function listSources(): readonly SourceInfo[] {\n return registry.listSources();\n}\n","/**\n * Testing a source without a network: `replayFetch` answers requests from recorded responses and\n * refuses any request it has no recording for. Browser-safe (no file system), so a graphty-element\n * story and a third party's tests use it the same way.\n */\n\n/**\n * One recorded exchange. Experimental.\n * @category Network sources\n */\nexport interface Recording {\n /** The request method. @defaultValue \"GET\" */\n readonly method?: string | undefined;\n /** The request URL. Query parameters match in any order. */\n readonly url: string;\n /** The request body, when it must match (JSON bodies compare as JSON). */\n readonly requestBody?: string | undefined;\n /**\n * true: the request must carry a credential; false: it must not. Absent: either. A credential\n * is an Authorization header, or a header or query parameter named in `secretHeaders` /\n * `secretQuery`; its value is never compared.\n */\n readonly credential?: boolean | undefined;\n /** The response status. @defaultValue 200 */\n readonly status?: number | undefined;\n /** The response headers. */\n readonly headers?: Readonly<Record<string, string>> | undefined;\n /** The response body: text, or a value sent as JSON. */\n readonly body?: unknown;\n}\n\n/**\n * The options of `replayFetch`. Experimental.\n * @category Network sources\n */\nexport interface ReplayOptions {\n /** What an unrecorded request does: \"throw\" (the only choice; the test fails). @defaultValue \"throw\" */\n readonly onUnrecorded?: \"throw\" | undefined;\n /** Query parameters that hold a credential: ignored when matching, counted as a credential. */\n readonly secretQuery?: readonly string[] | undefined;\n /** Request headers that hold a credential, beside Authorization. */\n readonly secretHeaders?: readonly string[] | undefined;\n}\n\n/**\n * One request `replayFetch` answered. Experimental.\n * @category Network sources\n */\nexport interface ReplayCall {\n /** The method. */\n readonly method: string;\n /** The URL, origin and path only. */\n readonly url: string;\n /** Whether a credential was sent. */\n readonly credential: boolean;\n}\n\n/**\n * A fetch that answers from recordings, plus the requests it answered. Experimental.\n * @category Network sources\n */\nexport type ReplayFetch = typeof fetch & {\n /** The requests answered, in order. */\n readonly calls: readonly ReplayCall[];\n};\n\n/**\n * A fetch that answers every request from recordings: the first unused recording that matches\n * (method, URL with its query in any order, body when recorded, and whether a credential was\n * sent), else the last one that matched, so a recording answers every repeat. A request with no\n * matching recording rejects with an Error naming its method and URL, which a source never\n * retries. Like fetch, a request whose signal is already aborted rejects with the signal's\n * reason. Pass it as the `fetch` option. Experimental.\n * @param recordings - the recorded exchanges\n * @param options - which headers and query parameters hold a credential\n * @returns the fetch\n * @example\n * ```ts\n * const fetch = replayFetch([{ url: \"https://example.com/api/people.json?team=core\", body: [{ id: \"ana\", knows: [] }] }]);\n * await loadFromSource(\"people\", { team: \"core\" }, { endpoint: \"https://example.com\", fetch });\n * ```\n * @category Network sources\n */\nexport function replayFetch(recordings: readonly Recording[], options: ReplayOptions = {}): ReplayFetch {\n const secretQuery = new Set(options.secretQuery ?? []);\n const secretHeaders = [\"authorization\", ...(options.secretHeaders ?? []).map((h) => h.toLowerCase())];\n const used = new Set<number>();\n const calls: ReplayCall[] = [];\n\n const key = (url: URL): string => {\n const params = [...url.searchParams].filter(([k]) => !secretQuery.has(k)).sort(compare);\n return `${url.origin}${url.pathname}?${new URLSearchParams(params).toString()}`;\n };\n\n const replay = async (input: string | URL | Request, init?: RequestInit): Promise<Response> => {\n const request = new Request(input, init);\n // like fetch: an aborted signal rejects with its reason before anything is answered\n request.signal.throwIfAborted();\n const url = new URL(request.url);\n const method = request.method.toUpperCase();\n const body = method === \"GET\" || method === \"HEAD\" ? \"\" : await request.clone().text();\n const credential =\n secretHeaders.some((h) => request.headers.has(h)) ||\n [...url.searchParams.keys()].some((k) => secretQuery.has(k));\n const wanted = key(url);\n const matches: number[] = [];\n recordings.forEach((r, i) => {\n if (\n (r.method ?? \"GET\").toUpperCase() === method &&\n key(new URL(r.url)) === wanted &&\n (r.credential === undefined || r.credential === credential) &&\n (r.requestBody === undefined || sameBody(r.requestBody, body))\n ) {\n matches.push(i);\n }\n });\n const index = matches.find((i) => !used.has(i)) ?? matches.at(-1);\n if (index === undefined) {\n throw new Error(`replayFetch: no recording for ${method} ${url.origin}${url.pathname}`);\n }\n used.add(index);\n calls.push({ method, url: `${url.origin}${url.pathname}`, credential });\n const r = recordings[index];\n const status = r.status ?? 200;\n const text = bodyText(r.body);\n const headers = new Headers(r.headers);\n if (text !== null && typeof r.body !== \"string\" && !headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n const nullBody = status === 204 || status === 304 || (status >= 300 && status < 400 && text === null);\n return new Response(nullBody ? null : text, { status, headers });\n };\n return Object.assign(replay, { calls });\n}\n\n/**\n * A recorded body as response text.\n * @param body - the recorded body\n * @returns the text, or null for no body\n */\nfunction bodyText(body: unknown): string | null {\n if (body === undefined || body === null) {\n return null;\n }\n return typeof body === \"string\" ? body : JSON.stringify(body);\n}\n\n/**\n * Compare two query entries by key, then value.\n * @param a - one entry\n * @param b - another\n * @returns the order\n */\nfunction compare(a: [string, string], b: [string, string]): number {\n return a[0] === b[0] ? a[1].localeCompare(b[1]) : a[0].localeCompare(b[0]);\n}\n\n/**\n * Whether two bodies are the same, as JSON when both parse.\n * @param recorded - the recorded body\n * @param sent - the sent body\n * @returns true when they match\n */\nfunction sameBody(recorded: string, sent: string): boolean {\n try {\n return JSON.stringify(JSON.parse(recorded)) === JSON.stringify(JSON.parse(sent));\n } catch {\n return recorded === sent;\n }\n}\n\n/**\n * A recording made from a real exchange, without its credential: the request's headers are never\n * kept, query parameters named in `secretQuery` are removed from the URL, and of the response only\n * the status, the Content-Type and the headers named in `keepHeaders` are kept. Experimental.\n * @param request - the request sent\n * @param response - its response (read; pass a clone to keep using it)\n * @param options - what to keep and drop\n * @param options.keepHeaders - response headers to keep beside Content-Type\n * @param options.secretQuery - query parameters removed from the URL\n * @returns the recording\n * @category Network sources\n */\nexport async function recordingFrom(\n request: Request,\n response: Response,\n options: { readonly keepHeaders?: readonly string[]; readonly secretQuery?: readonly string[] } = {},\n): Promise<Recording> {\n const headers: Record<string, string> = {};\n for (const name of [\"content-type\", ...(options.keepHeaders ?? [])]) {\n const value = response.headers.get(name);\n if (value !== null) {\n headers[name.toLowerCase()] = value;\n }\n }\n const url = new URL(request.url);\n for (const name of options.secretQuery ?? []) {\n url.searchParams.delete(name);\n }\n const method = request.method.toUpperCase();\n const requestBody = method === \"GET\" || method === \"HEAD\" ? undefined : await request.clone().text();\n return {\n method,\n url: url.toString(),\n ...(requestBody === undefined || requestBody === \"\" ? {} : { requestBody }),\n status: response.status,\n headers,\n body: await response.text(),\n };\n}\n"],"names":["sniff","attributes","s","t","e","a","n","i","al","r","v","ao","k","b","d","p","result","w","importerOptions","f","c","h","replay"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"graph-io.js","sources":["../src/common/line-format.ts","../src/common/compare.ts","../src/common/cell-budget.ts","../src/sources/builtins.ts","../src/sources/run.ts","../src/sources/registry.ts","../src/registry.ts","../src/sources/testing.ts"],"sourcesContent":["/**\n * defineLineFormat(): an importer for a text format with one node or one edge per line, built from\n * one function that reads a line. Everything else an importer must do (options, decoding, the\n * report and its counts, ids, direction, weights, attribute types, cancelling) is done here.\n */\n\nimport { GraphFormatError, type GraphSink, INVALID_INDEX } from \"@graphty/graph-format\";\n\nimport { type CommonImportOptions, type GraphImporter, type ImportInput, type ImportReport } from \"../types.js\";\nimport { BAD_LINE_CODE } from \"./codes.js\";\nimport { DirectionResolver } from \"./direction.js\";\nimport { IdCoercer } from \"./ids.js\";\nimport { LineReader, throwIfAborted } from \"./input.js\";\nimport { reportSinkOptions, reportUnusedOptions, resolveImportOptions } from \"./options.js\";\nimport { ImportReportBuilder, isAbortError, messageOf } from \"./report.js\";\nimport { TextCellWriter } from \"./text.js\";\nimport { parseWeightText } from \"./weights.js\";\n\n/**\n * Attribute values for a node or an edge added by defineLineFormat()'s `parseLine`.\n * @category Writing a format\n */\nexport type LineAttributes = Readonly<Record<string, string | number | boolean | null | undefined>>;\n\n/**\n * What `parseLine` adds a line's node or edge with.\n * @category Writing a format\n */\nexport interface LineGraph {\n /**\n * Add a node, or give a node that already exists more attributes. A `label` attribute is the\n * node's label, which `snapshot.nodes.byRole(\"label\")` finds; any other attribute's type (text,\n * integer, number, boolean) is worked out from its values, as for a CSV column.\n * @param id - the node id as written in the file\n * @param attributes - attribute values, such as `{ label: \"Alice\" }`\n */\n node(id: string, attributes?: LineAttributes): void;\n /**\n * Add an edge. A node it names that does not exist yet is added. The attribute that `weightFrom`\n * names (`weight` unless the caller passes another name) becomes the edge weight.\n * @param source - the source node id as written in the file\n * @param target - the target node id as written in the file\n * @param attributes - attribute values, such as `{ weight: \"2.5\" }`\n */\n edge(source: string, target: string, attributes?: LineAttributes): void;\n}\n\n/**\n * A text format with one node or one edge per line, for defineLineFormat().\n * @category Writing a format\n */\nexport interface LineFormat {\n /** The format name, which callers pass as `format`. */\n readonly format: string;\n /** The file extensions, with the dot (`[\".tgf\"]`); format detection matches them. */\n readonly extensions: readonly string[];\n /** MIME types the format is served as; none when left out. */\n readonly mimeTypes?: readonly string[] | undefined;\n /** Whether a file is directed when the caller passes no `defaultDirected`; false when left out. */\n readonly directed?: boolean | undefined;\n /** Lines that start with this text are skipped; `\"#\"` when left out, null to skip none. Blank lines are always skipped. */\n readonly comment?: string | null | undefined;\n /**\n * How sure you are that the first bytes of a file are this format, from 0 to 1. A file is\n * recognized by its content only when this returns 0.5 or more; without it, detection goes by\n * the file extension.\n */\n readonly sniff?: ((head: Uint8Array) => number) | undefined;\n /**\n * Read one line. `fields` is the line split on whitespace. Call `graph.node()` or `graph.edge()`\n * for what the line holds, and throw an Error to skip a line you cannot read: its message is\n * recorded as an `E_BAD_LINE` error with the line number.\n */\n readonly parseLine: (fields: readonly string[], graph: LineGraph, line: string) => void;\n}\n\n/** The common options a line format reads; a caller's other ones are reported as W_OPTION_IGNORED. */\nconst USED = new Set<keyof CommonImportOptions>([\"ids\", \"defaultDirected\", \"weightFrom\", \"addMissingNodes\"]);\n\n/**\n * Make an importer for a text format with one node or one edge per line. You write `parseLine`,\n * which reads one line; the importer handles every input graph-io takes, the options every importer\n * takes, the import report and its counts, cancelling and progress. Register the result with\n * `registry.registerImporter()`.\n * @example\n * ```ts\n * // \"a b\" is an edge, \"a\" alone is a node\n * const edgeList = defineLineFormat({\n * format: \"edges\",\n * extensions: [\".edges\"],\n * parseLine(fields, graph) {\n * if (fields.length === 1) {\n * graph.node(fields[0]);\n * } else if (fields.length === 2) {\n * graph.edge(fields[0], fields[1]);\n * } else {\n * throw new Error(\"expected one or two node ids\");\n * }\n * },\n * });\n * registry.registerImporter(edgeList);\n * ```\n * @param definition - the format: its name, extensions and `parseLine`\n * @returns the importer\n * @category Writing a format\n */\nexport function defineLineFormat(definition: LineFormat): GraphImporter {\n const { format, extensions, mimeTypes = [], directed = false, comment = \"#\", sniff, parseLine } = definition;\n const importer: GraphImporter = {\n format,\n extensions,\n mimeTypes,\n options: [],\n import: async (input: ImportInput, sink: GraphSink, options?: CommonImportOptions): Promise<ImportReport> => {\n const opts = resolveImportOptions(options, {\n ids: \"canonical\",\n defaultDirected: directed,\n weightFrom: \"weight\",\n });\n const report = new ImportReportBuilder(format, opts.errorLimit);\n reportSinkOptions(sink, options, report);\n reportUnusedOptions(options, report, USED);\n const ids = new IdCoercer(opts.ids);\n const edges = new DirectionResolver(sink, report, opts.onMixedDirection);\n const kind = opts.defaultDirected ? \"directed\" : \"undirected\";\n edges.setHeader(opts.defaultDirected);\n const attributes = new AttributeWriter(sink, report, opts.weightFrom);\n const write = (domain: \"node\" | \"edge\", row: number, values: LineAttributes | undefined): void => {\n attributes.write(domain, row, values);\n };\n const addNode = (id: string): number => {\n const nodeId = ids.text(id);\n if (sink.indexOf(nodeId) === INVALID_INDEX) {\n report.counts.nodes++;\n }\n return sink.addNode(nodeId);\n };\n let line = 0;\n const graph: LineGraph = {\n node: (id, attributes) => {\n write(\"node\", addNode(id), attributes);\n },\n edge: (source, target, attributes) => {\n const raw = opts.weightFrom === null ? undefined : attributes?.[opts.weightFrom];\n const weight = raw === null || raw === undefined ? undefined : parseWeightText(String(raw), report);\n const [s, t] = [ids.text(source), ids.text(target)];\n const added = new Set([s, t].filter((id) => sink.indexOf(id) === INVALID_INDEX)).size;\n const edge = edges.addEdge(s, t, kind, weight, { line });\n report.counts.nodes += added;\n report.counts.edges++;\n write(\"edge\", edge, attributes);\n },\n };\n const lines = new LineReader(input, report, opts);\n for await (const text of lines) {\n ({ line } = lines);\n if (line % 64 === 0) {\n throwIfAborted(opts.signal);\n }\n const trimmed = text.trim();\n if (trimmed === \"\" || (comment !== null && trimmed.startsWith(comment))) {\n continue;\n }\n try {\n parseLine(trimmed.split(/\\s+/), graph, text);\n } catch (err) {\n recordLineError(report, err, line);\n }\n }\n throwIfAborted(opts.signal);\n return report.finish();\n },\n };\n return Object.freeze(sniff === undefined ? importer : { ...importer, sniff });\n}\n\n/**\n * Record what a line's parser threw: a GraphFormatError with its own code, any other error as\n * BAD_LINE_CODE. A cancellation is rethrown.\n * @param report - the report\n * @param err - what the parser threw\n * @param line - the line number\n */\nfunction recordLineError(report: ImportReportBuilder, err: unknown, line: number): void {\n if (isAbortError(err)) {\n throw err;\n }\n if (err instanceof GraphFormatError) {\n report.recordError(err, { line });\n } else {\n report.error(\"parse-error\", BAD_LINE_CODE, err instanceof Error ? err.message : messageOf(err), { line });\n }\n}\n\n/** Writes the attributes a line format's parser gives a node or an edge into columns. */\nclass AttributeWriter {\n private readonly writers = { node: new Map<string, TextCellWriter>(), edge: new Map<string, TextCellWriter>() };\n\n /**\n * Create a writer.\n * @param sink - the sink\n * @param report - the report\n * @param weightFrom - the edge attribute read as the weight (not written as a column), or null\n */\n constructor(\n private readonly sink: GraphSink,\n private readonly report: ImportReportBuilder,\n private readonly weightFrom: string | null,\n ) {}\n\n /**\n * Write one element's attributes; null and undefined values are left unset.\n * @param domain - node or edge\n * @param row - the element's index\n * @param attributes - the attributes, or undefined\n */\n write(domain: \"node\" | \"edge\", row: number, attributes: LineAttributes | undefined): void {\n for (const [name, value] of Object.entries(attributes ?? {})) {\n if (value === null || value === undefined || (domain === \"edge\" && name === this.weightFrom)) {\n continue;\n }\n if (name === \"label\") {\n this.writeLabel(domain, row, String(value));\n continue;\n }\n let writer = this.writers[domain].get(name);\n if (writer === undefined) {\n writer = new TextCellWriter(name, domain, this.sink, this.report);\n this.writers[domain].set(name, writer);\n }\n writer.write(row, String(value));\n }\n }\n\n /**\n * Write a label: text, whatever it looks like, in the column that byRole(\"label\") finds.\n * @param domain - node or edge\n * @param row - the element's index\n * @param text - the label\n */\n private writeLabel(domain: \"node\" | \"edge\", row: number, text: string): void {\n const decl = { name: \"label\", dtype: \"string\", role: \"label\" } as const;\n if (domain === \"node\") {\n this.sink.setNodeValue(this.sink.declareNodeColumn(decl), row, text);\n } else {\n this.sink.setEdgeValue(this.sink.declareEdgeColumn(decl), row, text);\n }\n }\n}\n","/**\n * Compare two snapshots node by node, edge by edge and value by value, for testing a format plugin:\n * read a file, save it, read the saved file back, and compare. Every difference should be one that\n * the save's checkExport() notes announced.\n */\n\nimport { type Column, type GraphSnapshot } from \"@graphty/graph-format\";\n\n/**\n * One difference between two snapshots.\n * @category Plugin helpers\n */\nexport interface SnapshotDiff {\n /** Where: \"directed\", \"ids[3]\", \"nodes.label[4]\", \"edges.weight[0]\", \"extensions.temporal:node:price.rowCount\"... */\n readonly path: string;\n /** The value in the expected snapshot. */\n readonly expected: unknown;\n /** The value in the actual snapshot. */\n readonly actual: unknown;\n /** A one-line description. */\n readonly message: string;\n}\n\n/**\n * What compareSnapshots() compares.\n * @category Plugin helpers\n */\nexport interface CompareOptions {\n /** Column names to skip in every table (format-owned helpers an exporter adds, for instance). */\n readonly ignoreColumns?: readonly string[] | undefined;\n /** Column roles to skip in every table. */\n readonly ignoreRoles?: readonly string[] | undefined;\n /** Whether the actual snapshot may hold columns the expected one lacks (default true). */\n readonly allowExtraColumns?: boolean | undefined;\n /** Whether dtypes must match (default true); false compares values only. */\n readonly dtypes?: boolean | undefined;\n /** Whether roles must match (default true). */\n readonly roles?: boolean | undefined;\n /** Whether origin.type must match (default false). */\n readonly originType?: boolean | undefined;\n /** Absolute tolerance for numeric cell and weight comparisons (default 0: Object.is). */\n readonly tolerance?: number | undefined;\n /** Whether the explicit / defaulted status of weights must match (default true). */\n readonly weightExplicitness?: boolean | undefined;\n /** Whether extension tables are compared (default true). */\n readonly extensions?: boolean | undefined;\n /** Stop after this many differences (default 50). */\n readonly limit?: number | undefined;\n}\n\n/**\n * Compare two snapshots: the direction, the node ids, the edges, the weights and every attribute\n * value. Use it to test a format plugin: read a file, save it in your format, read the saved file\n * back, and compare the two graphs. Each difference has a `path` (\"ids[3]\", \"nodes.label[4]\",\n * \"edges.weight[0]\") and a one-line `message`; every one should match a note that `checkExport()`\n * returned for the save.\n * @example\n * ```ts\n * const notes = checkExport(original, \"pairs\");\n * const readBack = (await importGraph(await exportGraphToString(original, \"pairs\"), { format: \"pairs\" })).snapshot;\n * console.log(describeDiffs(compareSnapshots(original, readBack)));\n * ```\n * @param expected - the graph you saved\n * @param actual - the graph read back from the saved file\n * @param options - what to compare\n * @returns the differences, empty when the graphs are the same\n * @category Plugin helpers\n */\nexport function compareSnapshots(\n expected: GraphSnapshot,\n actual: GraphSnapshot,\n options: CompareOptions = {},\n): SnapshotDiff[] {\n const diffs: SnapshotDiff[] = [];\n const limit = options.limit ?? 50;\n const tolerance = options.tolerance ?? 0;\n const ctx: CompareContext = {\n options,\n diff: (path, e, a, message) => {\n diffs.push({\n path,\n expected: e,\n actual: a,\n message: message ?? `${path}: expected ${show(e)}, got ${show(a)}`,\n });\n if (diffs.length >= limit) {\n throw new LimitReached();\n }\n },\n same: (e, a) => valuesEqual(e, a, tolerance),\n };\n try {\n compareGraphs(expected, actual, ctx);\n } catch (err) {\n if (!(err instanceof LimitReached)) {\n throw err;\n }\n }\n return diffs;\n}\n\n/** Thrown by the recorder once the limit of differences is reached, to end the walk. */\nclass LimitReached extends Error {}\n\n/** What every comparison step shares: the options, the recorder and the value comparator. */\ninterface CompareContext {\n readonly options: CompareOptions;\n /** Records a difference (with a default message); throws LimitReached at the limit. */\n readonly diff: (path: string, e: unknown, a: unknown, message?: string) => void;\n /** Value equality under the tolerance. */\n readonly same: (e: unknown, a: unknown) => boolean;\n}\n\n/** A table shape both AttributeTable and extension tables satisfy. */\ninterface TableLike extends Iterable<Column> {\n readonly rowCount: number;\n names(): readonly string[];\n get(name: string): Column | null;\n}\n\n/**\n * Compare two snapshots step by step: the counts, the ids, the topology, the weights, the tables.\n * @param expected - the reference\n * @param actual - the snapshot under test\n * @param ctx - the comparison context\n */\nfunction compareGraphs(expected: GraphSnapshot, actual: GraphSnapshot, ctx: CompareContext): void {\n const { diff } = ctx;\n if (expected.directed !== actual.directed) {\n diff(\"directed\", expected.directed, actual.directed);\n }\n if (expected.nodeCount !== actual.nodeCount) {\n diff(\"nodeCount\", expected.nodeCount, actual.nodeCount);\n }\n if (expected.edgeCount !== actual.edgeCount) {\n diff(\"edgeCount\", expected.edgeCount, actual.edgeCount);\n }\n compareIds(expected, actual, diff);\n if (expected.nodeCount !== actual.nodeCount || expected.edgeCount !== actual.edgeCount) {\n return;\n }\n compareTopology(expected, actual, diff);\n compareWeights(expected, actual, ctx);\n compareTables(\"nodes\", expected.nodes, actual.nodes, ctx);\n compareTables(\"edges\", expected.edges, actual.edges, ctx);\n compareTables(\"graph\", expected.graph, actual.graph, ctx);\n if (ctx.options.extensions !== false) {\n compareExtensions(expected, actual, ctx);\n }\n}\n\n/**\n * Compare the node ids in index order.\n * @param expected - the reference\n * @param actual - the snapshot under test\n * @param diff - the recorder\n */\nfunction compareIds(expected: GraphSnapshot, actual: GraphSnapshot, diff: CompareContext[\"diff\"]): void {\n const expectedIds = expected.ids.toArray();\n const actualIds = actual.ids.toArray();\n const n = Math.min(expectedIds.length, actualIds.length);\n for (let i = 0; i < n; i++) {\n if (!Object.is(expectedIds[i], actualIds[i])) {\n diff(`ids[${i}]`, expectedIds[i], actualIds[i]);\n }\n }\n}\n\n/**\n * Compare the topology: the CSR arrays (identical when node order and edge order survived), then the\n * orientation of every logical edge.\n * @param expected - the reference\n * @param actual - the snapshot under test, with as many nodes and edges\n * @param diff - the recorder\n */\nfunction compareTopology(expected: GraphSnapshot, actual: GraphSnapshot, diff: CompareContext[\"diff\"]): void {\n if (!typedEqual(expected.rowPtr, actual.rowPtr)) {\n diff(\"rowPtr\", expected.rowPtr, actual.rowPtr, \"rowPtr differs\");\n }\n if (!typedEqual(expected.colIdx, actual.colIdx)) {\n diff(\"colIdx\", expected.colIdx, actual.colIdx, \"colIdx differs\");\n }\n const el = expected.edgeList();\n const al = actual.edgeList();\n for (let e = 0; e < expected.edgeCount; e++) {\n if (el.src[e] !== al.src[e] || el.dst[e] !== al.dst[e]) {\n diff(`edge[${e}]`, `${el.src[e]}->${el.dst[e]}`, `${al.src[e]}->${al.dst[e]}`);\n }\n }\n}\n\n/**\n * Compare the weights of two snapshots: the exact weight column when both have one, the 32-bit\n * weights otherwise.\n * @param expected - the reference\n * @param actual - the snapshot under test\n * @param ctx - the comparison context\n */\nfunction compareWeights(expected: GraphSnapshot, actual: GraphSnapshot, ctx: CompareContext): void {\n if (expected.flags.weighted !== actual.flags.weighted) {\n ctx.diff(\"flags.weighted\", expected.flags.weighted, actual.flags.weighted);\n return;\n }\n if (!expected.flags.weighted) {\n return;\n }\n const eShadow = expected.edges.byRole(\"weight\");\n const aShadow = actual.edges.byRole(\"weight\");\n if (eShadow !== null && aShadow !== null) {\n compareExactWeights(expected.edgeCount, eShadow, aShadow, ctx);\n return;\n }\n if (ctx.options.weightExplicitness !== false && (eShadow === null) !== (aShadow === null)) {\n ctx.diff(\n \"weightColumn\",\n eShadow !== null,\n aShadow !== null,\n \"one snapshot has a role-weight column, the other does not\",\n );\n }\n const ew = expected.edgeList().weights;\n const aw = actual.edgeList().weights;\n for (let e = 0; e < expected.edgeCount; e++) {\n const ev = ew === null ? 1 : ew[e];\n const av = aw === null ? 1 : aw[e];\n if (!ctx.same(ev, av)) {\n ctx.diff(`weight[${e}]`, ev, av);\n }\n }\n}\n\n/**\n * Compare the exact weight columns of two snapshots: which edges have an explicit weight, and its value.\n * @param edgeCount - the number of edges\n * @param expected - the reference's weight column\n * @param actual - the weight column under test\n * @param ctx - the comparison context\n */\nfunction compareExactWeights(edgeCount: number, expected: Column, actual: Column, ctx: CompareContext): void {\n for (let e = 0; e < edgeCount; e++) {\n const eSet = expected.isSet(e);\n const aSet = actual.isSet(e);\n if (ctx.options.weightExplicitness !== false && eSet !== aSet) {\n ctx.diff(`weightExplicit[${e}]`, eSet, aSet);\n } else if (eSet && aSet && !ctx.same(expected.value(e), actual.value(e))) {\n ctx.diff(`weight[${e}]`, expected.value(e), actual.value(e));\n }\n }\n}\n\n/**\n * Compare the extension tables: which exist, their row counts and their columns.\n * @param expected - the reference\n * @param actual - the snapshot under test\n * @param ctx - the comparison context\n */\nfunction compareExtensions(expected: GraphSnapshot, actual: GraphSnapshot, ctx: CompareContext): void {\n for (const [name, table] of expected.extensions) {\n const other = actual.extensions.get(name);\n if (other === undefined) {\n ctx.diff(`extensions.${name}`, \"present\", \"absent\");\n } else if (table.rowCount === other.rowCount) {\n compareTables(`extensions.${name}`, table, other, ctx);\n } else {\n ctx.diff(`extensions.${name}.rowCount`, table.rowCount, other.rowCount);\n }\n }\n if (ctx.options.allowExtraColumns === false) {\n for (const name of actual.extensions.keys()) {\n if (!expected.extensions.has(name)) {\n ctx.diff(`extensions.${name}`, \"absent\", \"present\");\n }\n }\n }\n}\n\n/**\n * Compare the columns of one table.\n * @param label - the table name for paths\n * @param expected - the reference table\n * @param actual - the table under test\n * @param ctx - the comparison context\n */\nfunction compareTables(label: string, expected: TableLike, actual: TableLike, ctx: CompareContext): void {\n const ignoreNames = new Set(ctx.options.ignoreColumns ?? []);\n const ignoreRoles = new Set(ctx.options.ignoreRoles ?? []);\n // the role-weight shadow column is compared by the weights step, not as a declared column\n const skip = (column: Column): boolean => {\n const { name, role } = column.meta;\n return (\n ignoreNames.has(name) ||\n (role !== null && (ignoreRoles.has(role) || (label === \"edges\" && role === \"weight\")))\n );\n };\n for (const column of expected) {\n if (skip(column)) {\n continue;\n }\n const path = `${label}.${column.meta.name}`;\n const other = actual.get(column.meta.name);\n if (other === null) {\n ctx.diff(path, \"present\", \"absent\", `${path}: column missing after round trip`);\n } else {\n compareColumn(path, column, other, ctx);\n }\n }\n if (ctx.options.allowExtraColumns === false) {\n for (const column of actual) {\n if (!skip(column) && expected.get(column.meta.name) === null) {\n const path = `${label}.${column.meta.name}`;\n ctx.diff(path, \"absent\", \"present\", `${path}: extra column after round trip`);\n }\n }\n }\n}\n\n/**\n * Compare one column: its declaration, then every cell.\n * @param path - the column's path for messages\n * @param column - the reference column\n * @param other - the column under test\n * @param ctx - the comparison context\n */\nfunction compareColumn(path: string, column: Column, other: Column, ctx: CompareContext): void {\n compareDeclaration(path, column, other, ctx);\n if (column.length !== other.length) {\n ctx.diff(`${path}.length`, column.length, other.length);\n return;\n }\n for (let r = 0; r < column.length; r++) {\n const eSet = column.isSet(r);\n const aSet = other.isSet(r);\n if (eSet !== aSet) {\n ctx.diff(`${path}[${r}]`, eSet ? column.value(r) : undefined, aSet ? other.value(r) : undefined);\n } else if (eSet) {\n const ev = cellValue(column, r);\n const av = cellValue(other, r);\n if (!ctx.same(ev, av)) {\n ctx.diff(`${path}[${r}]`, ev, av);\n }\n }\n }\n}\n\n/**\n * Compare what two columns declare: dtype, item dtype, components, role and origin type, as the\n * options ask.\n * @param path - the column's path for messages\n * @param column - the reference column\n * @param other - the column under test\n * @param ctx - the comparison context\n */\nfunction compareDeclaration(path: string, column: Column, other: Column, ctx: CompareContext): void {\n const { options, diff } = ctx;\n const e = column.meta;\n const a = other.meta;\n if (options.dtypes !== false) {\n for (const key of [\"dtype\", \"itemDtype\", \"components\"] as const) {\n if (e[key] !== a[key]) {\n diff(`${path}.${key}`, e[key], a[key]);\n }\n }\n }\n if (options.roles !== false && e.role !== a.role) {\n diff(`${path}.role`, e.role, a.role);\n }\n const eType = e.origin?.type ?? null;\n const aType = a.origin?.type ?? null;\n if (options.originType === true && eType !== aType) {\n diff(`${path}.origin.type`, eType, aType);\n }\n}\n\n/**\n * The comparable value of a set cell: list rows through sliceOf, json rows through values, the\n * typed accessor otherwise (a components > 1 subarray becomes a plain array).\n * @param column - the column\n * @param row - the row\n * @returns the value\n */\nfunction cellValue(column: Column, row: number): unknown {\n switch (column.dtype) {\n case \"list\":\n return [...column.sliceOf(row)];\n case \"json\":\n return column.values[row];\n default: {\n const value = column.value(row);\n return ArrayBuffer.isView(value) ? Array.from(value as ArrayLike<number>) : value;\n }\n }\n}\n\n/**\n * Deep equality with a numeric tolerance (for the tests).\n * @param e - expected\n * @param a - actual\n * @param tolerance - absolute tolerance for numbers\n * @returns true when equal\n */\nexport function valuesEqual(e: unknown, a: unknown, tolerance: number): boolean {\n if (typeof e === \"number\" && typeof a === \"number\") {\n if (Object.is(e, a)) {\n return true;\n }\n return Number.isFinite(e) && Number.isFinite(a) && Math.abs(e - a) <= tolerance;\n }\n if (Array.isArray(e) || ArrayBuffer.isView(e)) {\n const ea = Array.from(e as ArrayLike<unknown>);\n if (!(Array.isArray(a) || ArrayBuffer.isView(a))) {\n return false;\n }\n const aa = Array.from(a as ArrayLike<unknown>);\n return ea.length === aa.length && ea.every((v, i) => valuesEqual(v, aa[i], tolerance));\n }\n if (typeof e === \"object\" && e !== null && typeof a === \"object\" && a !== null) {\n const eo = e as Record<string, unknown>;\n const ao = a as Record<string, unknown>;\n const keys = Object.keys(eo);\n if (keys.length !== Object.keys(ao).length) {\n return false;\n }\n return keys.every((k) => Object.hasOwn(ao, k) && valuesEqual(eo[k], ao[k], tolerance));\n }\n return Object.is(e, a);\n}\n\n/**\n * Element-wise equality of two typed arrays.\n * @param a - one array\n * @param b - the other\n * @returns true when same length and contents\n */\nfunction typedEqual(a: ArrayLike<number>, b: ArrayLike<number>): boolean {\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * A short text of a value for messages.\n * @param v - the value\n * @returns JSON when possible, else String()\n */\nfunction show(v: unknown): string {\n if (ArrayBuffer.isView(v)) {\n const items = Array.from(v as unknown as ArrayLike<number>);\n return `[${items.slice(0, 8).join(\", \")}${items.length > 8 ? \", ...\" : \"\"}]`;\n }\n try {\n const text = JSON.stringify(v);\n return text ?? String(v);\n } catch {\n return String(v);\n }\n}\n\n/**\n * The differences compareSnapshots() found, one per line, for printing.\n * @param diffs - the differences\n * @returns one line per difference, \"no differences\" when empty\n * @category Plugin helpers\n */\nexport function describeDiffs(diffs: readonly SnapshotDiff[]): string {\n return diffs.length === 0 ? \"no differences\" : diffs.map((d) => ` - ${d.message}`).join(\"\\n\");\n}\n","/**\n * A memory guard for the builder importGraph() fills. graph-format stores every attribute as a dense\n * column, one slot per node (or edge) whether or not that element has a value, so a file whose nodes\n * each carry a differently named attribute holds n values but allocates n x n slots: a few hundred\n * kilobytes of input can need gigabytes. The guard counts the slots that hold no value and stops the\n * import once they pass a limit. A dense file has almost no empty slots, so it is never stopped\n * however large it is.\n */\n\nimport {\n type ColumnDecl,\n type ColumnHandle,\n GraphBuilder,\n type GraphBuilderOptions,\n GraphFormatError,\n type NodeId,\n} from \"@graphty/graph-format\";\n\nimport { describe } from \"./options.js\";\nimport { plural } from \"./plural.js\";\nimport { ImportReportBuilder } from \"./report.js\";\n\n/**\n * Import stopped for allocating too many empty attribute slots.\n * @category Issue and loss codes\n */\nexport const TOO_MANY_EMPTY_CELLS_CODE = \"E_TOO_MANY_EMPTY_CELLS\";\n\n/** The default limit: 2^24 empty slots, about 130 MB of f64 columns. */\nconst DEFAULT_MAX_EMPTY_CELLS = 2 ** 24;\n\n/**\n * Resolve the maxEmptyCells option.\n * @param value - the caller's value\n * @returns a non-negative integer or Infinity\n * @throws GraphFormatError E_UNSUPPORTED for anything else\n * @category Plugin helpers\n */\nexport function maxEmptyCellsOption(value: unknown): number {\n if (value === undefined) {\n return DEFAULT_MAX_EMPTY_CELLS;\n }\n if (typeof value === \"number\" && value >= 0 && (Number.isInteger(value) || value === Infinity)) {\n return value;\n }\n throw new GraphFormatError(\n \"E_UNSUPPORTED\",\n `option maxEmptyCells: ${describe(value)} is not a non-negative integer or Infinity`,\n { option: \"maxEmptyCells\", found: value },\n );\n}\n\n/**\n * A GraphBuilder that throws an ImportError once its attribute columns hold too many empty slots.\n * @category Plugin helpers\n */\nexport class CellBudgetBuilder extends GraphBuilder {\n private readonly nodeColumns = new Set<number>();\n private readonly edgeColumns = new Set<number>();\n private values = 0;\n\n /**\n * Create a builder with a limit.\n * @param options - the builder options\n * @param format - the format being read, for the error's report\n * @param maxEmptyCells - the most empty slots allowed\n */\n constructor(\n options: GraphBuilderOptions,\n private readonly format: string,\n private readonly maxEmptyCells: number,\n ) {\n super(options);\n }\n\n /**\n * Add a node, then check the limit (its row adds a slot to every node column).\n * @param id - the node id\n * @returns the node index\n */\n override addNode(id: NodeId): number {\n const index = super.addNode(id);\n this.checkBudget();\n return index;\n }\n\n /**\n * Add an edge, then check the limit (its row adds a slot to every edge column).\n * @param source - source id\n * @param target - target id\n * @param weight - the weight\n * @returns the edge index\n */\n override addEdge(source: NodeId, target: NodeId, weight?: number): number {\n const edge = super.addEdge(source, target, weight);\n this.checkBudget();\n return edge;\n }\n\n /**\n * Declare a node column, then check the limit.\n * @param decl - the declaration\n * @returns the column handle\n */\n override declareNodeColumn(decl: ColumnDecl): ColumnHandle {\n const handle = super.declareNodeColumn(decl);\n this.nodeColumns.add(handle);\n this.checkBudget();\n return handle;\n }\n\n /**\n * Declare an edge column, then check the limit.\n * @param decl - the declaration\n * @returns the column handle\n */\n override declareEdgeColumn(decl: ColumnDecl): ColumnHandle {\n const handle = super.declareEdgeColumn(decl);\n this.edgeColumns.add(handle);\n this.checkBudget();\n return handle;\n }\n\n /**\n * Set a node cell (a new name declares a column), then check the limit.\n * @param column - the handle or name\n * @param index - the node index\n * @param value - the value\n */\n override setNodeValue(column: ColumnHandle | string, index: number, value: unknown): void {\n super.setNodeValue(column, index, value);\n this.nodeColumns.add(typeof column === \"string\" ? this.nodeColumn(column) : column);\n this.count(value);\n }\n\n /**\n * Set an edge cell (a new name declares a column), then check the limit.\n * @param column - the handle or name\n * @param edge - the edge index\n * @param value - the value\n */\n override setEdgeValue(column: ColumnHandle | string, edge: number, value: unknown): void {\n super.setEdgeValue(column, edge, value);\n this.edgeColumns.add(typeof column === \"string\" ? this.edgeColumn(column) : column);\n this.count(value);\n }\n\n /**\n * Count a written value and check the budget.\n * @param value - the value; null and undefined unset a slot and do not count\n */\n private count(value: unknown): void {\n if (value !== null && value !== undefined) {\n this.values++;\n }\n this.checkBudget();\n }\n\n /**\n * Throw when the columns' slots minus the values written pass the limit.\n * @throws ImportError E_TOO_MANY_EMPTY_CELLS\n */\n private checkBudget(): void {\n const slots = this.nodeColumns.size * this.nodeBound + this.edgeColumns.size * this.edgeBound;\n const empty = slots - this.values;\n if (empty > this.maxEmptyCells) {\n new ImportReportBuilder(this.format, Infinity).fail(\n TOO_MANY_EMPTY_CELLS_CODE,\n `the attributes are too sparse: ${this.nodeColumns.size} node and ${this.edgeColumns.size} edge ` +\n `attribute columns over ${this.nodeBound} node${plural(this.nodeBound)} and ${this.edgeBound} edge${plural(this.edgeBound)} would ` +\n `allocate more than ${this.maxEmptyCells} slots that hold no value; pass a larger ` +\n `maxEmptyCells (or Infinity) to read the file anyway`,\n undefined,\n { emptyCells: empty, maxEmptyCells: this.maxEmptyCells },\n );\n }\n }\n}\n","/**\n * The built-in sources, registered as lazy sources: their descriptors are here, their code loads\n * on first use through a dynamic import of the source's subpath.\n */\n\nimport { CYPHER_DESCRIPTOR, NEO4J_DESCRIPTOR, NEPTUNE_DESCRIPTOR } from \"./cypher/descriptor.js\";\nimport {\n CYPHER_SOURCE_ID,\n NDEX_SOURCE_ID,\n NEO4J_SOURCE_ID,\n NEPTUNE_SOURCE_ID,\n OPENALEX_SOURCE_ID,\n REST_SOURCE_ID,\n SPARQL_SOURCE_ID,\n} from \"./ids.js\";\nimport { NDEX_DESCRIPTOR } from \"./ndex/descriptor.js\";\nimport { OPENALEX_DESCRIPTOR, REST_DESCRIPTOR } from \"./rest/descriptor.js\";\nimport { SPARQL_DESCRIPTOR } from \"./sparql/descriptor.js\";\nimport { type LazySource } from \"./types.js\";\n\n/**\n * The seven built-in sources, each loading its subpath on first use.\n * @returns the lazy sources, in catalog order\n */\nexport function builtinSources(): readonly LazySource[] {\n return [\n {\n id: NDEX_SOURCE_ID,\n descriptor: NDEX_DESCRIPTOR,\n load: async () => (await import(\"./ndex/index.js\")).ndexSource,\n },\n {\n id: CYPHER_SOURCE_ID,\n descriptor: CYPHER_DESCRIPTOR,\n load: async () => (await import(\"./cypher/index.js\")).cypherSource,\n },\n {\n id: NEO4J_SOURCE_ID,\n descriptor: NEO4J_DESCRIPTOR,\n load: async () => (await import(\"./cypher/index.js\")).neo4jSource,\n },\n {\n id: NEPTUNE_SOURCE_ID,\n descriptor: NEPTUNE_DESCRIPTOR,\n load: async () => (await import(\"./cypher/index.js\")).neptuneSource,\n },\n {\n id: REST_SOURCE_ID,\n descriptor: REST_DESCRIPTOR,\n load: async () => (await import(\"./rest/index.js\")).restMappingSource,\n },\n {\n id: OPENALEX_SOURCE_ID,\n descriptor: OPENALEX_DESCRIPTOR,\n load: async () => (await import(\"./rest/index.js\")).openalexSource,\n },\n {\n id: SPARQL_SOURCE_ID,\n descriptor: SPARQL_DESCRIPTOR,\n load: async () => (await import(\"./sparql/index.js\")).sparqlSource,\n },\n ];\n}\n","/**\n * Running a source (design sections 2, 3 and 5): the checks before any request, the three read\n * paths (`records` through the record methods, `file` through the format importers, `import`\n * straight into the sink), the caps between pages, `idPrefix`, the versioned cursor, and the\n * report's `source` member. graph-io keeps no state between calls.\n */\n\nimport { type GraphSink, INVALID_INDEX, type NodeId, type U32 } from \"@graphty/graph-format\";\n\nimport { MISSING_ID_CODE } from \"../common/codes.js\";\nimport { readBytes, throwIfAborted } from \"../common/input.js\";\nimport { ImportReportBuilder } from \"../common/report.js\";\nimport { readZipDirectory, readZipEntry } from \"../common/zip.js\";\nimport { type FormatRegistry } from \"../registry.js\";\nimport { SNIFF_HEAD_BYTES } from \"../sniff.js\";\nimport { type CommonImportOptions, ImportError, type ImportInput, type ImportReport } from \"../types.js\";\nimport { type CreatedContext, createSourceContext, detectRuntime, LimitStop } from \"./context.js\";\nimport { credentialQuery, originOf } from \"./credentials.js\";\nimport { checkParams } from \"./define.js\";\nimport { failOn, warnOn } from \"./fail.js\";\nimport { SOURCE_FORMAT_PREFIX } from \"./ids.js\";\nimport {\n type GraphSource,\n type LoadFromSourceOptions,\n type RecordBatch,\n type SourceCursor,\n type SourceFile,\n} from \"./types.js\";\n\n/** The cursor key graph-io adds, holding the source's descriptor version. */\nconst CURSOR_VERSION_KEY = \"~v\";\n\n/** The options that belong to the source functions, never to an importer. */\nconst SOURCE_OPTION_KEYS: ReadonlySet<string> = new Set([\n \"endpoint\",\n \"credential\",\n \"cursor\",\n \"limits\",\n \"retry\",\n \"idPrefix\",\n \"allowInsecure\",\n \"fetch\",\n \"userAgent\",\n \"builder\",\n \"freeze\",\n \"onProgress\",\n \"signal\",\n]);\n\n/** The statuses whose failure on a later page keeps the pages before it. */\nconst AUTH_CODES: ReadonlySet<string> = new Set([\"E_SOURCE_AUTH\", \"E_SOURCE_FORBIDDEN\"]);\n\n/** What a call needs set up before the source runs. */\ninterface Prepared {\n /** The load's report. */\n readonly report: ImportReportBuilder;\n /** The context and its controls. */\n readonly created: CreatedContext;\n /** The params with the descriptor's defaults. */\n readonly params: Record<string, unknown>;\n /** The sink wrapper's counters, set once the sink is known. */\n readonly counts: { nodes: Set<number>; edgesAtStart: number; sink: GraphSink | null };\n /** The query parameter the call's credential is sent in, which a cursor never keeps; null for none. */\n readonly secretQuery: string | null;\n}\n\n/**\n * The report format name of a source load.\n * @param id - the source id\n * @returns `\"source:<id>\"`\n */\nexport function sourceFormat(id: string): string {\n return `${SOURCE_FORMAT_PREFIX}${id}`;\n}\n\n/**\n * The cursor handed back to the caller: the source's own, with its version added.\n * @param next - the source's cursor\n * @param version - the descriptor version\n * @returns the caller's cursor\n */\nexport function wrapCursor(next: SourceCursor | null | undefined, version: number): SourceCursor | null {\n return next === null || next === undefined ? null : Object.freeze({ ...next, [CURSOR_VERSION_KEY]: version });\n}\n\n/**\n * Check every rule that holds before a request is sent and build the context.\n * @param source - the loaded source\n * @param rawParams - the caller's params\n * @param options - the caller's options\n * @param unit - what progress counts\n * @returns the report, context and params\n */\nfunction prepare(\n source: GraphSource<never>,\n rawParams: Readonly<Record<string, unknown>>,\n options: LoadFromSourceOptions,\n unit: \"items\" | \"bytes\",\n): Prepared {\n const { descriptor } = source;\n const version = descriptor?.version ?? 1;\n const report = new ImportReportBuilder(sourceFormat(source.id), options.errorLimit ?? 100);\n checkRuntime(source, report);\n checkParams(rawParams, descriptor, report);\n const params: Record<string, unknown> = {};\n for (const p of descriptor?.params ?? []) {\n if (p.default !== undefined) {\n params[p.name] = p.default;\n }\n }\n Object.assign(params, rawParams);\n\n const endpoint = resolveEndpoint(options.endpoint ?? descriptor?.defaultEndpoint ?? null, report);\n if (options.credential?.origins.length === 0 && endpoint === null) {\n failOn(report, \"E_SOURCE_PARAM\", \"a credential needs an endpoint or its own origins\", {\n name: \"credential\",\n reason: \"credential-unbound\",\n });\n }\n const cursor = resumeCursor(options.cursor, version, report);\n\n const counts: Prepared[\"counts\"] = { nodes: new Set<number>(), edgesAtStart: 0, sink: null };\n const created = createSourceContext({\n id: source.id,\n descriptor,\n options,\n report,\n endpoint,\n cursor,\n unit,\n counts: () => ({\n nodes: counts.nodes.size,\n edges: counts.sink === null ? 0 : counts.sink.edgeCount - counts.edgesAtStart,\n }),\n });\n const secretQuery = options.credential === undefined ? null : credentialQuery(options.credential);\n return { report, created, params, counts, secretQuery };\n}\n\n/**\n * Refuse a source that cannot run here: a runtime it does not support, or a secure context it needs.\n * @param source - the loaded source\n * @param report - the load's report\n */\nfunction checkRuntime(source: GraphSource<never>, report: ImportReportBuilder): void {\n const { descriptor } = source;\n const runtime = detectRuntime();\n const support = descriptor?.runtimes?.[runtime];\n if (support?.supported === false) {\n failOn(report, \"E_SOURCE_RUNTIME\", `source ${source.id} cannot run in ${runtime}`, {\n runtime,\n reason: support.reason ?? \"unsupported\",\n });\n }\n if (\n descriptor?.needs?.secureContext === true &&\n runtime === \"browser\" &&\n (globalThis as { isSecureContext?: boolean }).isSecureContext === false\n ) {\n failOn(report, \"E_SOURCE_RUNTIME\", `source ${source.id} needs a secure context`, {\n runtime,\n reason: \"needs-secure-context\",\n });\n }\n}\n\n/**\n * The endpoint as a URL, refusing one that is not a URL or carries a user name or password.\n * @param given - the endpoint given, if any\n * @param report - the load's report\n * @returns the URL, or null without one\n */\nfunction resolveEndpoint(given: string | URL | null, report: ImportReportBuilder): URL | null {\n if (given === null) {\n return null;\n }\n let endpoint: URL;\n try {\n endpoint = new URL(given);\n } catch {\n failOn(report, \"E_SOURCE_PARAM\", \"the endpoint is not a URL\", { name: \"endpoint\", reason: \"type\" });\n }\n if (endpoint.username !== \"\" || endpoint.password !== \"\") {\n failOn(report, \"E_SOURCE_PARAM\", \"the endpoint may not carry a user name or password\", {\n name: \"endpoint\",\n reason: \"credentials-in-url\",\n });\n }\n return endpoint;\n}\n\n/**\n * The source's own cursor from the caller's, refusing one another descriptor version made.\n * @param given - the caller's cursor, if any\n * @param version - the descriptor version\n * @param report - the load's report\n * @returns the source's cursor, or null\n */\nfunction resumeCursor(\n given: SourceCursor | null | undefined,\n version: number,\n report: ImportReportBuilder,\n): SourceCursor | null {\n if (given === undefined || given === null) {\n return null;\n }\n const { [CURSOR_VERSION_KEY]: recorded, ...rest } = given;\n if (recorded !== undefined && recorded !== version) {\n failOn(report, \"E_SOURCE_PARAM\", \"the cursor was made by another version of the source\", {\n name: \"cursor\",\n reason: \"stale-cursor\",\n });\n }\n return Object.freeze(rest);\n}\n\n/**\n * Wrap a sink so every node id gets the prefix and the caps can count the distinct nodes written.\n * @param sink - the caller's sink or the builder\n * @param prepared - the call's counters\n * @param prefix - the idPrefix, if any\n * @returns the wrapped sink\n */\nexport function wrapSink(sink: GraphSink, prepared: Prepared, prefix: string | undefined): GraphSink {\n prepared.counts.sink = sink;\n prepared.counts.edgesAtStart = sink.edgeCount;\n const seen = prepared.counts.nodes;\n const id = (value: NodeId): NodeId => (prefix === undefined || prefix === \"\" ? value : `${prefix}${String(value)}`);\n const node = (index: number): number => {\n seen.add(index);\n return index;\n };\n // an edge may add its end nodes (addMissingNodes)\n const ends = (edge: number): number => {\n const [a, b] = sink.edgeEndpoints(edge);\n seen.add(a);\n seen.add(b);\n return edge;\n };\n return new Proxy(sink, {\n get(target, key): unknown {\n switch (key) {\n case \"addNode\":\n return (v: NodeId): number => node(target.addNode(id(v)));\n case \"addNodeRecord\":\n return (v: NodeId, attrs: Readonly<Record<string, unknown>>): number =>\n node(target.addNodeRecord(id(v), attrs));\n case \"addNodes\":\n return (ids: Iterable<NodeId>, out?: U32): U32 => {\n const result = target.addNodes(Array.from(ids, id), out);\n result.forEach((i) => seen.add(i));\n return result;\n };\n case \"addEdge\":\n return (s: NodeId, t: NodeId, w?: number): number => ends(target.addEdge(id(s), id(t), w));\n case \"addEdgeRecord\":\n return (\n s: NodeId,\n t: NodeId,\n attrs: Readonly<Record<string, unknown>>,\n weightKey?: string | null,\n ): number => ends(target.addEdgeRecord(id(s), id(t), attrs, weightKey));\n case \"indexOf\":\n return (v: NodeId): number => target.indexOf(id(v));\n default: {\n const value = Reflect.get(target, key, target) as unknown;\n return typeof value === \"function\" ? (value as (...a: unknown[]) => unknown).bind(target) : value;\n }\n }\n },\n });\n}\n\n/**\n * The options a format importer gets from a file source's load.\n * @param options - the caller's options\n * @param signal - the context's signal\n * @returns the importer options\n */\nfunction importerOptions(options: LoadFromSourceOptions, signal: AbortSignal): CommonImportOptions {\n const out: Record<string, unknown> = { signal };\n for (const [key, value] of Object.entries(options)) {\n if (!SOURCE_OPTION_KEYS.has(key)) {\n out[key] = value;\n }\n }\n return out;\n}\n\n/**\n * Write graph facts: `name`, `description` and `modified` strings to the graph's meta, any other\n * scalar (but `directed`) as a graph value.\n * @param sink - the sink\n * @param meta - the facts\n */\nfunction writeMeta(sink: GraphSink, meta: Readonly<Record<string, unknown>>): void {\n const patch: Record<string, string> = {};\n for (const [key, value] of Object.entries(meta)) {\n if ((key === \"name\" || key === \"description\" || key === \"modified\") && typeof value === \"string\") {\n patch[key] = value;\n } else if (\n key !== \"directed\" &&\n (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\")\n ) {\n sink.setGraphValue(key, value);\n }\n }\n if (Object.keys(patch).length > 0) {\n sink.setMeta(patch);\n }\n}\n\n/**\n * Write one page of records into the sink.\n * @param batch - the page\n * @param sink - the wrapped sink\n * @param source - the source (for its record keys)\n * @param prepared - the call\n * @param first - whether this is the first page\n */\nfunction writeBatch(\n batch: RecordBatch,\n sink: GraphSink,\n source: GraphSource<never>,\n prepared: Prepared,\n first: boolean,\n): void {\n const idKey = source.idKey ?? \"id\";\n const sourceKey = source.sourceKey ?? \"source\";\n const targetKey = source.targetKey ?? \"target\";\n const meta = batch.meta ?? {};\n if (first && typeof meta.directed === \"boolean\" && sink.edgeCount === 0) {\n sink.setDirected(meta.directed);\n }\n writeMeta(sink, meta);\n const n = writeNodes(batch, sink, idKey, prepared);\n writeEdges(batch, sink, sourceKey, targetKey, prepared, n);\n}\n\n/**\n * Write a page's node records.\n * @param batch - the page\n * @param sink - the wrapped sink\n * @param idKey - the record key holding the id\n * @param prepared - the call\n * @returns how many records were visited, for the abort check's cadence\n */\nfunction writeNodes(batch: RecordBatch, sink: GraphSink, idKey: string, prepared: Prepared): number {\n const { report } = prepared;\n const { signal } = prepared.created.ctx;\n let n = 0;\n for (const record of batch.nodes ?? []) {\n if (n++ % 64 === 0) {\n throwIfAborted(signal);\n }\n const { [idKey]: id, ...attrs } = record;\n if (typeof id !== \"string\" && typeof id !== \"number\") {\n report.error(\"missing-value\", MISSING_ID_CODE, `a node record has no ${idKey}`);\n report.counts.skippedNodes++;\n continue;\n }\n try {\n sink.addNodeRecord(id, attrs);\n report.counts.nodes++;\n } catch (err) {\n report.recordError(err, { element: String(id) });\n report.counts.skippedNodes++;\n }\n }\n return n;\n}\n\n/**\n * Write a page's edge records.\n * @param batch - the page\n * @param sink - the wrapped sink\n * @param sourceKey - the record key holding the source id\n * @param targetKey - the record key holding the target id\n * @param prepared - the call\n * @param start - records visited so far, for the abort check's cadence\n */\nfunction writeEdges(\n batch: RecordBatch,\n sink: GraphSink,\n sourceKey: string,\n targetKey: string,\n prepared: Prepared,\n start: number,\n): void {\n const { report } = prepared;\n const { signal } = prepared.created.ctx;\n let n = start;\n let edgeIds: ReturnType<GraphSink[\"declareEdgeColumn\"]> | null = null;\n for (const record of batch.edges ?? []) {\n if (n++ % 64 === 0) {\n throwIfAborted(signal);\n }\n const s = record[sourceKey];\n const t = record[targetKey];\n const edgeId = record.id;\n const fields = Object.fromEntries(\n Object.entries(record).filter(([k]) => k !== sourceKey && k !== targetKey && k !== \"id\"),\n );\n if ((typeof s !== \"string\" && typeof s !== \"number\") || (typeof t !== \"string\" && typeof t !== \"number\")) {\n report.error(\"missing-value\", MISSING_ID_CODE, `an edge record has no ${sourceKey} or ${targetKey}`);\n report.counts.skippedEdges++;\n continue;\n }\n try {\n const e = sink.addEdgeRecord(s, t, fields);\n if (typeof edgeId === \"string\" || typeof edgeId === \"number\") {\n edgeIds ??= edgeIdColumn(sink);\n sink.setEdgeValue(edgeIds, e, String(edgeId));\n }\n report.counts.edges++;\n } catch (err) {\n report.recordError(err, { element: `${String(s)} -> ${String(t)}` });\n report.counts.skippedEdges++;\n }\n }\n}\n\n/**\n * The origin of an endpoint, or \"\" without one.\n * @param endpoint - the endpoint\n * @returns its origin\n */\nfunction endpointOrigin(endpoint: URL | null): string {\n return endpoint === null ? \"\" : originOf(endpoint);\n}\n\n/**\n * The edge id column, declared on first use.\n * @param sink - the sink\n * @returns its handle\n */\nfunction edgeIdColumn(sink: GraphSink): ReturnType<GraphSink[\"declareEdgeColumn\"]> {\n const existing = sink.edgeColumn(\"id\");\n return existing === INVALID_INDEX\n ? sink.declareEdgeColumn({ name: \"id\", dtype: \"string\", role: \"id\", nullable: true })\n : existing;\n}\n\n/**\n * The page iterator of a records source: its async iterable, or its one batch.\n * @param out - what `records()` returned\n * @returns an iterator over the pages\n */\nfunction pages(out: Promise<RecordBatch> | AsyncIterable<RecordBatch>): AsyncIterator<RecordBatch> {\n if (Symbol.asyncIterator in out) {\n return out[Symbol.asyncIterator]();\n }\n let done = false;\n return {\n async next(): Promise<IteratorResult<RecordBatch>> {\n if (done) {\n return { done: true, value: undefined };\n }\n done = true;\n return { done: false, value: await out };\n },\n };\n}\n\n/**\n * Decide what a failed page means: a cap reached or a later page needing a credential stops the\n * load and keeps what was read (warning for the credential); anything else is rethrown.\n * @param err - what the page threw\n * @param page - how many pages were written before it\n * @param prepared - the call\n */\nfunction stopOrThrow(err: unknown, page: number, prepared: Prepared): void {\n if (err instanceof LimitStop) {\n return;\n }\n if (page > 0 && err instanceof ImportError && AUTH_CODES.has(String(err.issue?.code))) {\n const p = err.issue?.params ?? {};\n warnOn(prepared.report, \"W_SOURCE_AUTH\", \"a later page needs a credential; the pages before it are kept\", {\n origin: typeof p.origin === \"string\" ? p.origin : endpointOrigin(prepared.created.ctx.endpoint),\n status: typeof p.status === \"number\" ? p.status : null,\n });\n return;\n }\n throw err;\n}\n\n/**\n * Run a records source into a sink.\n * @param source - the source\n * @param sink - the wrapped sink\n * @param prepared - the call\n * @returns where to resume, as the source gave it\n */\nasync function runRecords(\n source: GraphSource<never>,\n sink: GraphSink,\n prepared: Prepared,\n): Promise<SourceCursor | null> {\n const { ctx } = prepared.created;\n const records = source.records as (p: unknown, c: typeof ctx) => Promise<RecordBatch> | AsyncIterable<RecordBatch>;\n const iterator = pages(records(prepared.params, ctx));\n let next: SourceCursor | null = ctx.cursor;\n let page = 0;\n let stopped = false;\n try {\n for (;;) {\n let step: IteratorResult<RecordBatch>;\n try {\n step = await iterator.next();\n } catch (err) {\n stopOrThrow(err, page, prepared);\n stopped = true;\n return next;\n }\n if (step.done === true) {\n return page === 0 ? null : next;\n }\n writeBatch(step.value, sink, source, prepared, page === 0);\n page++;\n next = step.value.next ?? null;\n ctx.progress(prepared.report.counts.nodes + prepared.report.counts.edges, undefined, \"items\");\n if (ctx.limits.reached()) {\n stopped = true;\n return next;\n }\n }\n } finally {\n if (stopped) {\n await iterator.return?.().catch(() => undefined);\n }\n }\n}\n\n/**\n * The importer input of a file source's body, gunzipped or unzipped when its name says so.\n * @param file - what the source returned\n * @param formats - the registry, for choosing a zip entry\n * @param signal - the signal\n * @returns the input and its hints\n */\nasync function fileInput(\n file: SourceFile,\n formats: FormatRegistry,\n signal: AbortSignal,\n): Promise<{ input: ImportInput; filename: string | undefined; mimeType: string | undefined }> {\n let input: ImportInput = file.body instanceof Response ? (file.body.body ?? new Uint8Array(0)) : file.body;\n let { filename } = file;\n let mimeType =\n file.mimeType ??\n (file.body instanceof Response ? (file.body.headers.get(\"content-type\") ?? undefined) : undefined);\n const gzip = /\\.gz$/i.test(filename ?? \"\") || /gzip/i.test(mimeType ?? \"\");\n const zip = /\\.zip$/i.test(filename ?? \"\") || /\\/(x-)?zip\\b/i.test(mimeType ?? \"\");\n if (gzip) {\n const stream =\n input instanceof ReadableStream\n ? input\n : new Response((await bytesOf(input, signal)) as Uint8Array<ArrayBuffer>).body;\n input = (stream ?? new Response(\"\").body ?? new ReadableStream()).pipeThrough(\n new DecompressionStream(\"gzip\") as unknown as ReadableWritablePair<Uint8Array, Uint8Array>,\n );\n filename = filename?.replace(/\\.gz$/i, \"\");\n mimeType = undefined;\n } else if (zip) {\n const bytes = await bytesOf(input, signal);\n const entry = readZipDirectory(bytes).find((e) => !e.directory && formats.sniff({ filename: e.name }) !== null);\n if (entry === undefined) {\n throw new ImportError(\"the zip holds no graph file\", new ImportReportBuilder(\"zip\", 0).finish());\n }\n input = await readZipEntry(bytes, entry, { signal, maxBytes: Number.MAX_SAFE_INTEGER, maxRatio: 1000 });\n filename = entry.name;\n mimeType = undefined;\n }\n return { input, filename, mimeType };\n}\n\n/**\n * The bytes of an input.\n * @param input - the input\n * @param signal - the signal\n * @returns the bytes\n */\nasync function bytesOf(input: ImportInput, signal: AbortSignal): Promise<Uint8Array> {\n return (await readBytes(input, { signal })) ?? new TextEncoder().encode(typeof input === \"string\" ? input : \"\");\n}\n\n/**\n * Run a file source into a sink through the format importers.\n * @param source - the source\n * @param sink - the wrapped sink\n * @param prepared - the call\n * @param formats - the registry\n * @param options - the caller's options\n * @returns the format the file was read as\n */\nasync function runFile(\n source: GraphSource<never>,\n sink: GraphSink,\n prepared: Prepared,\n formats: FormatRegistry,\n options: LoadFromSourceOptions,\n): Promise<string> {\n const { ctx } = prepared.created;\n const read = source.file as (p: unknown, c: typeof ctx) => Promise<SourceFile>;\n const file = await read(prepared.params, ctx);\n const { input, filename, mimeType } = await fileInput(file, formats, ctx.signal);\n let { format } = file;\n let body: ImportInput = input;\n if (format === undefined) {\n const bytes = await bytesOf(input, ctx.signal);\n format = formats.sniff({ filename, mimeType, head: bytes.subarray(0, SNIFF_HEAD_BYTES) })?.format;\n body = bytes;\n if (format === undefined) {\n failOn(prepared.report, \"E_SOURCE_RESPONSE\", \"the file is in no format graph-io reads\", {\n expected: \"graph-file\",\n contentType: mimeType ?? null,\n });\n }\n }\n const importer = formats.importer(format);\n prepared.report.include(await importer.import(body, sink, importerOptions(options, ctx.signal)));\n writeMeta(sink, file.meta ?? {});\n return format;\n}\n\n/** What a run into a sink produced. */\ninterface SinkRun {\n /** The report, with its `source` member. */\n readonly report: ImportReport;\n /** The format: `source:<id>`, or the format a file source resolved to. */\n readonly format: string;\n}\n\n/**\n * Run a source's read method into a sink.\n * @param source - the loaded source\n * @param params - the caller's params\n * @param sink - where to write\n * @param options - the caller's options\n * @param formats - the registry, for file sources\n * @returns the report and the format\n */\nexport async function runIntoSink(\n source: GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n sink: GraphSink,\n options: LoadFromSourceOptions,\n formats: FormatRegistry,\n): Promise<SinkRun> {\n const prepared = prepare(source, params, options, typeof source.file === \"function\" ? \"bytes\" : \"items\");\n const { ctx } = prepared.created;\n const version = source.descriptor?.version ?? 1;\n const wrapped = wrapSink(sink, prepared, options.idPrefix);\n try {\n if (typeof source.records === \"function\") {\n const next = await runRecords(source, wrapped, prepared);\n throwIfAborted(ctx.signal);\n return {\n report: withSource(prepared.report.finish(), prepared, wrapCursor(next, version)),\n format: sourceFormat(source.id),\n };\n }\n if (typeof source.file === \"function\") {\n const format = await runFile(source, wrapped, prepared, formats, options);\n return { report: withSource(prepared.report.finish(), prepared, null), format };\n }\n const run = source.import as (p: unknown, s: GraphSink, c: typeof ctx) => Promise<ImportReport>;\n const report = await stopAtLimit(run(prepared.params, wrapped, ctx), prepared);\n throwIfAborted(ctx.signal);\n return {\n report: withSource(report, prepared, wrapCursor(prepared.created.state.finish?.next, version)),\n format: sourceFormat(source.id),\n };\n } catch (err) {\n throw settle(err, prepared);\n } finally {\n prepared.created.dispose();\n }\n}\n\n/**\n * Run an optional method of a source (expand, probe, list, validate) with a context.\n * @param source - the loaded source\n * @param feature - the method name\n * @param params - the params checked against the descriptor\n * @param options - the caller's options\n * @param call - calls the method with the context\n * @returns what the method returned, and the call's state\n */\nexport async function runMethod<T>(\n source: GraphSource<never>,\n feature: \"expand\" | \"probe\" | \"list\" | \"validate\",\n params: Readonly<Record<string, unknown>>,\n options: LoadFromSourceOptions,\n call: (prepared: Prepared) => Promise<T>,\n): Promise<T> {\n if (typeof source[feature] !== \"function\") {\n failOn(\n new ImportReportBuilder(sourceFormat(source.id), 0),\n \"E_SOURCE_UNSUPPORTED\",\n `source ${source.id} has no ${feature}`,\n {\n feature,\n },\n );\n }\n const prepared = prepare(source, params, options, \"items\");\n try {\n const out = await call(prepared);\n throwIfAborted(prepared.created.ctx.signal);\n return out;\n } catch (err) {\n throw settle(err, prepared);\n } finally {\n prepared.created.dispose();\n }\n}\n\n/**\n * Add the `source` member to a report.\n * @param report - the report\n * @param prepared - the call\n * @param next - where to resume, as the caller sees it\n * @returns the report with its source member\n */\nexport function withSource(report: ImportReport, prepared: Prepared, next: SourceCursor | null): ImportReport {\n const own = prepared.report.finish();\n const cursor = prepared.secretQuery === null || next === null ? next : withoutParam(next, prepared.secretQuery);\n // issues the context recorded (retries, limits) that a source's own report does not hold\n const missing = own.issues.filter((i) => !report.issues.includes(i));\n return Object.freeze({\n ...report,\n issues: missing.length === 0 ? report.issues : Object.freeze([...report.issues, ...missing]),\n warningCount: report.warningCount + missing.filter((i) => i.severity === \"warning\").length,\n errorCount: report.errorCount + missing.filter((i) => i.severity === \"error\").length,\n source: prepared.created.info(cursor),\n });\n}\n\n/**\n * A cursor without a query parameter in any URL it holds: a next-page link a service returns\n * repeats the API key the request carried, and a cursor is saved where a credential never is.\n * The credential is sent again with every request, so the next page does not need it there.\n * @param value - the cursor, or a value inside it\n * @param name - the parameter\n * @returns the value without it\n */\nfunction withoutParam<T>(value: T, name: string): T {\n if (typeof value === \"string\" && /^https?:\\/\\//i.test(value)) {\n const url = new URL(value);\n if (!url.searchParams.has(name)) {\n return value;\n }\n url.searchParams.delete(name);\n return url.href as T;\n }\n if (Array.isArray(value)) {\n return Object.freeze(value.map((each: unknown) => withoutParam(each, name))) as T;\n }\n if (typeof value === \"object\" && value !== null) {\n return Object.freeze(\n Object.fromEntries(Object.entries(value).map(([key, each]) => [key, withoutParam(each, name)])),\n ) as T;\n }\n return value;\n}\n\n/**\n * What a failed call throws: the signal's reason when it aborted, an ImportError with the source\n * info attached, or the error itself.\n * @param err - what was thrown\n * @param prepared - the call\n * @returns the error to throw\n */\nfunction settle(err: unknown, prepared: Prepared): unknown {\n const { signal } = prepared.created.ctx;\n if (signal.aborted) {\n return signal.reason as unknown;\n }\n if (err instanceof LimitStop) {\n // a cap reached where nothing can be kept (a file cut short): the load fails with the cap\n return settle(limitError(err, prepared), prepared);\n }\n if (err instanceof ImportError && err.report.source === undefined) {\n const withInfo = new ImportError(\n err.message,\n { ...err.report, source: prepared.created.info(null) },\n err.details,\n );\n withInfo.stack = err.stack;\n return withInfo;\n }\n return err;\n}\n\n/**\n * The E_SOURCE_LIMIT error of a cap that stopped a load which can keep nothing.\n * @param stop - the cap reached\n * @param prepared - the call\n * @returns the error\n */\nfunction limitError(stop: LimitStop, prepared: Prepared): unknown {\n try {\n return failOn(prepared.report, \"E_SOURCE_LIMIT\", stop.message, { limit: stop.limit, value: stop.value });\n } catch (err) {\n return err;\n }\n}\n\n/**\n * The report of an import or expand source, or, when a cap stopped it under \"stop\" (a LimitStop\n * raised by ctx.fetch that the source did not catch), the report of what it wrote so far.\n * @param run - the source's call\n * @param prepared - the call\n * @returns the report\n */\nexport async function stopAtLimit(run: Promise<ImportReport>, prepared: Prepared): Promise<ImportReport> {\n try {\n return await run;\n } catch (err) {\n if (err instanceof LimitStop) {\n return prepared.report.finish();\n }\n throw err;\n }\n}\n","/**\n * The source registry (design section 3): sources by id, in their own name space beside the\n * formats. Lazy sources are registered by descriptor and load their code on first use, so listing\n * sources loads none. A FormatRegistry holds one, so one object holds formats and sources.\n */\n\nimport { type GraphBuilder, type GraphSink } from \"@graphty/graph-format\";\n\nimport { type FormatRegistry, type ImportGraphResult } from \"../registry.js\";\nimport { type ImportReport } from \"../types.js\";\nimport { checkLazySource, checkSource } from \"./define.js\";\nimport { failAlone } from \"./fail.js\";\nimport { runIntoSink, runMethod, sourceFormat, stopAtLimit, withSource, wrapCursor, wrapSink } from \"./run.js\";\nimport {\n type ExpandRequest,\n type GraphSource,\n type LazySource,\n type LoadFromSourceOptions,\n type SourceDescriptor,\n type SourceFreshness,\n type SourceInfo,\n type SourceListing,\n type SourceListQuery,\n type SourceProbe,\n type SourceValidators,\n} from \"./types.js\";\n\n/** A registered source: loaded, or a lazy one with its descriptor. */\ninterface Entry {\n /** The descriptor known without loading. */\n readonly descriptor: SourceDescriptor;\n /** The lazy registration, if any. */\n readonly lazy: LazySource | null;\n /** The loaded source. */\n source: GraphSource<never> | null;\n /** The load in flight. */\n loading: Promise<GraphSource<never>> | null;\n}\n\n/**\n * Whether a registration is a lazy source rather than a source.\n * @param value - the registration\n * @returns true for a LazySource\n */\nfunction isLazy(value: GraphSource<never> | LazySource): value is LazySource {\n const v = value as { load?: unknown; records?: unknown; file?: unknown; import?: unknown };\n return typeof v.load === \"function\" && v.records === undefined && v.file === undefined && v.import === undefined;\n}\n\n/** What a SourceRegistry borrows from its FormatRegistry: building and freezing a graph. */\ninterface SourceBuilding {\n /**\n * A builder seeded from the load options.\n * @param options - the options\n * @param format - the report format name\n * @returns the builder\n */\n readonly newBuilder: (options: LoadFromSourceOptions, format: string) => GraphBuilder;\n /**\n * Freeze a filled builder into a load result.\n * @param format - the result's format\n * @param builder - the builder\n * @param report - the report\n * @param options - the options\n * @returns the result\n */\n readonly freeze: (\n format: string,\n builder: GraphBuilder,\n report: ImportReport,\n options: LoadFromSourceOptions,\n ) => ImportGraphResult;\n}\n\n/**\n * The sources of one FormatRegistry. Experimental.\n * @category Network sources\n */\nexport class SourceRegistry {\n private readonly entries = new Map<string, Entry>();\n\n /**\n * Create one for a format registry, whose importers read `file` sources.\n * @param formats - the format registry\n * @param building - how it builds and freezes graphs\n */\n constructor(\n private readonly formats: FormatRegistry,\n private readonly building: SourceBuilding,\n ) {}\n\n /**\n * Register a source or a lazy source. A malformed one, or an id already taken, throws an\n * ImportError with E_SOURCE_INVALID.\n * @param source - the source\n */\n register(source: GraphSource<never> | LazySource): void {\n if (isLazy(source)) {\n checkLazySource(source);\n } else {\n checkSource(source);\n }\n if (this.entries.has(source.id)) {\n failAlone(\"E_SOURCE_INVALID\", `a source with id ${source.id} is already registered`, {\n id: source.id,\n reason: \"duplicate\",\n });\n }\n const lazy = isLazy(source) ? source : null;\n this.entries.set(source.id, {\n descriptor: source.descriptor ?? { plainName: source.id, params: [] },\n lazy,\n source: lazy === null ? (source as GraphSource<never>) : null,\n loading: null,\n });\n }\n\n /**\n * Whether a source id is registered.\n * @param id - the id\n * @returns true when registered\n */\n has(id: string): boolean {\n return this.entries.has(id);\n }\n\n /**\n * Every registered source, without loading any code.\n * @returns one entry per source, in registration order\n */\n list(): readonly SourceInfo[] {\n return Object.freeze(\n [...this.entries].map(([id, e]) =>\n Object.freeze({ id, descriptor: e.descriptor, loaded: e.source !== null }),\n ),\n );\n }\n\n /**\n * A source by id, loading a lazy one; a source object passes through after its checks.\n * @param source - the id or the source\n * @returns the loaded source\n */\n async resolve(source: string | GraphSource<never>): Promise<GraphSource<never>> {\n if (typeof source !== \"string\") {\n checkSource(source);\n return source;\n }\n const entry = this.entries.get(source);\n if (entry === undefined) {\n return failAlone(\n \"E_SOURCE_UNKNOWN\",\n `no source has id ${JSON.stringify(source)}`,\n { id: source, known: [...this.entries.keys()] },\n sourceFormat(source),\n );\n }\n if (entry.source !== null) {\n return entry.source;\n }\n const lazy = entry.lazy as LazySource;\n entry.loading ??= lazy.load().then(\n (loaded) => {\n if (loaded.id !== lazy.id) {\n failAlone(\"E_SOURCE_INVALID\", `lazy source ${lazy.id} loaded a source with id ${loaded.id}`, {\n id: lazy.id,\n reason: \"lazy\",\n });\n }\n checkSource(loaded, lazy.descriptor);\n entry.source = loaded.descriptor === undefined ? { ...loaded, descriptor: lazy.descriptor } : loaded;\n return entry.source;\n },\n (err: unknown) => {\n entry.loading = null;\n throw err;\n },\n );\n return entry.loading;\n }\n\n /**\n * Load a graph from a source.\n * @param source - the id or the source\n * @param params - its params\n * @param options - endpoint, credential, cursor, caps and the import options\n * @returns the graph and the report\n */\n async load(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n options: LoadFromSourceOptions = {},\n ): Promise<ImportGraphResult> {\n const resolved = await this.resolve(source);\n const builder = this.building.newBuilder(options, sourceFormat(resolved.id));\n const { report, format } = await runIntoSink(resolved, params, builder, options, this.formats);\n return this.building.freeze(format, builder, report, options);\n }\n\n /**\n * Load from a source into a sink you own.\n * @param source - the id or the source\n * @param params - its params\n * @param sink - where to write\n * @param options - the options\n * @returns the report\n */\n async import(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n sink: GraphSink,\n options: LoadFromSourceOptions = {},\n ): Promise<ImportReport> {\n const resolved = await this.resolve(source);\n return (await runIntoSink(resolved, params, sink, options, this.formats)).report;\n }\n\n /**\n * Fetch the neighborhood of some nodes: a snapshot of only what was fetched.\n * @param source - the id or the source\n * @param request - the seeds and how far to go\n * @param options - the options\n * @returns the fetched part and the report\n */\n async expand(\n source: string | GraphSource<never>,\n request: ExpandRequest<Readonly<Record<string, unknown>>>,\n options: LoadFromSourceOptions = {},\n ): Promise<ImportGraphResult> {\n const resolved = await this.resolve(source);\n const builder: GraphBuilder = this.building.newBuilder(options, sourceFormat(resolved.id));\n const report = await runMethod(resolved, \"expand\", request.params, options, async (prepared) => {\n const sink = wrapSink(builder, prepared, options.idPrefix);\n const run = resolved.expand?.({ ...request, params: prepared.params } as never, sink, prepared.created.ctx);\n const out = await stopAtLimit(run as Promise<ImportReport>, prepared);\n return withSource(\n out,\n prepared,\n wrapCursor(prepared.created.state.finish?.next, resolved.descriptor?.version ?? 1),\n );\n });\n return this.building.freeze(sourceFormat(resolved.id), builder, report, options);\n }\n\n /**\n * Check params and credential without loading.\n * @param source - the id or the source\n * @param params - its params\n * @param options - the options\n * @returns what the service said\n */\n async probe(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n options: LoadFromSourceOptions = {},\n ): Promise<SourceProbe> {\n const resolved = await this.resolve(source);\n return runMethod(\n resolved,\n \"probe\",\n params,\n options,\n (prepared) => resolved.probe?.(prepared.params as never, prepared.created.ctx) as Promise<SourceProbe>,\n );\n }\n\n /**\n * Search what a source holds.\n * @param source - the id or the source\n * @param query - the search\n * @param options - the options\n * @returns one page of results\n */\n async search(\n source: string | GraphSource<never>,\n query: SourceListQuery<Readonly<Record<string, unknown>>>,\n options: LoadFromSourceOptions = {},\n ): Promise<SourceListing> {\n const resolved = await this.resolve(source);\n // a search narrows by some params, so required ones are not checked\n const partial: SourceDescriptor | undefined =\n resolved.descriptor === undefined\n ? undefined\n : {\n ...resolved.descriptor,\n params: resolved.descriptor.params.map((p) => ({ ...p, required: false })),\n };\n return runMethod(\n { ...resolved, descriptor: partial },\n \"list\",\n query.params,\n options,\n (prepared) =>\n resolved.list?.(\n { ...query, params: prepared.params } as never,\n prepared.created.ctx,\n ) as Promise<SourceListing>,\n );\n }\n\n /**\n * Tell whether data loaded earlier changed.\n * @param source - the id or the source\n * @param params - the params it was loaded with\n * @param seen - the validators recorded then\n * @param options - the options\n * @returns whether it changed\n */\n async validate(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n seen: SourceValidators,\n options: LoadFromSourceOptions = {},\n ): Promise<SourceFreshness> {\n const resolved = await this.resolve(source);\n return runMethod(\n resolved,\n \"validate\",\n params,\n options,\n (prepared) =>\n resolved.validate?.(prepared.params as never, seen, prepared.created.ctx) as Promise<SourceFreshness>,\n );\n }\n}\n","/**\n * The importer / exporter registry: the built-in formats\n * registered by name, `sniff()` over them, and the two conveniences for callers who do not own a\n * sink: `importGraph()` sniffs the format, creates a builder seeded from the common options\n * (`directed: true` as a placeholder; the importer sets the real value), imports and freezes;\n * `exportGraph()` looks the exporter up by name. A caller who owns a builder uses the importer\n * objects directly (the subpath exports) and this module never touches their sink.\n */\n\nimport {\n type FreezeOptions,\n type FreezeReport,\n GraphBuilder,\n type GraphBuilderOptions,\n GraphFormatError,\n type GraphSink,\n type GraphSnapshot,\n} from \"@graphty/graph-format\";\n\nimport { CellBudgetBuilder, maxEmptyCellsOption } from \"./common/cell-budget.js\";\nimport {\n EDGES_MERGED_CODE,\n EMPTY_INPUT_CODE,\n FETCH_CODE,\n OPTION_IGNORED_CODE,\n SELF_LOOPS_DROPPED_CODE,\n STYLES_NOT_IMPORTED_CODE,\n UNKNOWN_OPTION_CODE,\n WEIGHT_NOT_FOUND_CODE,\n} from \"./common/codes.js\";\nimport { abortable, foreignKind, lockReader, normalizeInput, throwIfAborted } from \"./common/input.js\";\nimport { chooseGraph, resolveImportOptions } from \"./common/options.js\";\nimport { agree, plural } from \"./common/plural.js\";\nimport { ImportReportBuilder, isAbortError, messageOf } from \"./common/report.js\";\nimport { collectBytes } from \"./common/writer.js\";\nimport { csvExporter, csvImporter } from \"./formats/csv/index.js\";\nimport { cxExporter, cxImporter } from \"./formats/cx/index.js\";\nimport { cx2Exporter, cx2Importer } from \"./formats/cx2/index.js\";\nimport { cysExporter, cysImporter } from \"./formats/cys/index.js\";\nimport { dotExporter, dotImporter } from \"./formats/dot/index.js\";\nimport { gexfExporter, gexfImporter } from \"./formats/gexf/index.js\";\nimport { gmlExporter, gmlImporter } from \"./formats/gml/index.js\";\nimport { graphmlExporter, graphmlImporter } from \"./formats/graphml/index.js\";\nimport { jsonExporter, jsonImporter } from \"./formats/json/index.js\";\nimport { neo4jExporter, neo4jImporter } from \"./formats/neo4j/index.js\";\nimport { oboExporter, oboImporter } from \"./formats/obo/index.js\";\nimport { pajekExporter, pajekImporter } from \"./formats/pajek/index.js\";\nimport { xgmmlExporter, xgmmlImporter } from \"./formats/xgmml/index.js\";\nimport { type FormatName, rankFormats, SNIFF_HEAD_BYTES, type SniffHints, type SniffResult } from \"./sniff.js\";\nimport { builtinSources } from \"./sources/builtins.js\";\nimport { type SourceParamsMap } from \"./sources/params.js\";\nimport { SourceRegistry } from \"./sources/registry.js\";\nimport {\n type ExpandRequest,\n type GraphSource,\n type LazySource,\n type LoadFromSourceOptions,\n type SourceFreshness,\n type SourceInfo,\n type SourceListing,\n type SourceListQuery,\n type SourceProbe,\n type SourceValidators,\n} from \"./sources/types.js\";\nimport { extractStyles, type StyleImportOptions } from \"./styles/io/generic.js\";\nimport { isKeptGraphtyProperty, prepareStyleExport } from \"./styles/io/writer.js\";\nimport type { ExtractedStyles } from \"./styles/types.js\";\nimport {\n type CommonExportOptions,\n type CommonImportOptions,\n type ExportCapabilities,\n type GraphChoiceOptions,\n type GraphExporter,\n type GraphImporter,\n type GraphListing,\n ImportError,\n type ImportInput,\n type ImportIssue,\n type ImportReport,\n type IssueCategory,\n type LossNote,\n} from \"./types.js\";\n\n/**\n * The input is in no format graph-io can read (or none of the formats you registered, for your own FormatRegistry).\n * Pass `format` when you know what the file is.\n * @category Issue and loss codes\n */\nexport const UNKNOWN_FORMAT_CODE = \"E_UNKNOWN_FORMAT\";\n\n/**\n * Registered importer whose sniff() threw while the format was being chosen; that importer was treated as not\n * recognizing the input (a defect in that importer).\n * @category Issue and loss codes\n */\nexport const SNIFF_FAILED_CODE = \"W_SNIFF_FAILED\";\n\n/**\n * The `builder` option of importGraph(): settings for building the graph that the common import\n * options do not cover. `weighted`: \"auto\" (the default) gives the graph weights when any edge has\n * one, true always does (every weight 1 when the file has none), false never does. `expectedNodes`\n * and `expectedEdges`: how many nodes and edges to make room for up front, which saves time on a\n * large file whose size you know.\n * @category Loading\n */\nexport type BuilderSeed = Omit<\n GraphBuilderOptions,\n \"directed\" | \"addMissingNodes\" | \"duplicateEdges\" | \"selfLoops\" | \"weightDtype\"\n>;\n\n/**\n * The options of importGraph(), importAllGraphs(), listGraphs() and loadFromFile(): the common\n * import options, the format and the hints used to detect it, the graph to read from a file that\n * holds several, and any format-specific option (`delimiter`, `dialect`, ...), which reaches the\n * importer unchanged.\n * @category Loading\n */\nexport interface ImportGraphOptions extends CommonImportOptions, GraphChoiceOptions {\n /**\n * The format to read the input as (\"graphml\", \"csv\", ...; `listFormats()` names them all), or\n * \"auto\" to work it out from `filename`, `mimeType` and the first bytes of the input. Name it to\n * be strict: detection reads a file graph-io cannot place as the closest format it recognizes.\n * @defaultValue \"auto\"\n */\n readonly format?: FormatName | \"auto\" | undefined;\n /**\n * The file name or full path the input came from; only its extension is used, as a format hint.\n * loadFromUrl() takes it from the URL and loadFromFile() from a File's name when you do not pass\n * it.\n */\n readonly filename?: string | null | undefined;\n /**\n * The MIME type the input was served as, a format hint. loadFromUrl() takes it from the\n * response's Content-Type and loadFromFile() from the Blob's `type` when you do not pass it.\n */\n readonly mimeType?: string | null | undefined;\n /**\n * Settings for building the graph: `weighted` (\"auto\", true or false: whether the graph gets\n * weights), `expectedNodes` and `expectedEdges` (room to make up front for a large file). Most\n * programs never set it.\n */\n readonly builder?: BuilderSeed | undefined;\n /**\n * Settings for the last step of an import, which turns what was read into the snapshot:\n * `label` (a name for debugging, read back as `snapshot.label`), `prepare` (views of the graph\n * to compute up front, such as `[\"reverse\"]`), `checksum` (record checksums, which\n * `snapshot.validate({ checksum: true })` compares later to catch changed memory) and `profile` (record how long each step took, in `result.freeze.timings`). Most\n * programs never set it.\n */\n readonly freeze?: FreezeOptions | undefined;\n /**\n * The most attribute slots that hold no value the import may allocate before it stops with an\n * ImportError whose `issue.code` is E_TOO_MANY_EMPTY_CELLS. Every attribute is a column with one slot per node (or edge), so a file\n * whose nodes each have a differently named attribute would otherwise need nodes x attributes\n * memory. Infinity turns the check off. Files whose elements mostly share their attributes are\n * never stopped.\n * @defaultValue 16777216\n */\n readonly maxEmptyCells?: number | undefined;\n /**\n * Read the file's styles too: `true`, or `{ toolDefaults: false }` to leave out the defaults of the program\n * that wrote the file. The styles are in `result.styles`; the graph, the report and every export are the same\n * either way.\n * @defaultValue false\n */\n readonly styles?: boolean | StyleImportOptions | undefined;\n /** Format-specific options, passed to the importer as they are. */\n readonly [formatOption: string]: unknown;\n}\n\n/**\n * What importGraph(), loadFromUrl() and loadFromFile() return.\n * @category Loading\n */\nexport interface ImportGraphResult {\n /** The format the input was read as (\"graphml\", ...). */\n readonly format: string;\n /**\n * How the format was detected (the candidate's `confidence` and what matched), or null when you\n * named the format. Most callers can ignore it. For the JSON dialect that was read, call\n * `jsonShapeOf(snapshot)` from `@graphty/graph-io/json`.\n */\n readonly sniff: SniffResult | null;\n /**\n * The graph. `snapshot.nodeCount`, `snapshot.edgeCount`, attribute tables and so on come from\n * the `@graphty/graph-format` package.\n */\n readonly snapshot: GraphSnapshot;\n /**\n * What happened during the import. `errorCount` counts skipped elements (see `errorLimit`,\n * default 100); `warningCount` counts elements that were kept but changed; `issues` lists both;\n * `counts.skippedNodes` / `counts.skippedEdges` say how much is missing from `snapshot`.\n */\n readonly report: ImportReport;\n /**\n * What the last step of the import did to the graph: `mergedEdges` (parallel edges merged by\n * `duplicateEdges`), `droppedSelfLoops` (removed by `selfLoops: \"drop\"`), and `timings` when you\n * passed `freeze: { profile: true }`. Both counts are also reported as warnings, so most callers\n * can ignore it. It is not enumerable, so `console.log(result)` and `{ ...result }` leave it out.\n */\n readonly freeze: FreezeReport;\n /**\n * The file's styles, when you passed the `styles` option: the rules that reproduce how the program that wrote\n * the file draws each node and edge, read by the importer that read the file. Null when the file has none.\n * Absent without the option.\n */\n readonly styles?: ExtractedStyles | null;\n}\n\n/**\n * Options for loadFromUrl(): everything importGraph() accepts, plus the fetch request settings.\n * @example\n * ```ts\n * await loadFromUrl(\"/api/graph.csv\", { request: { headers: { Authorization: token } }, delimiter: \";\" });\n * ```\n * @category Loading\n */\nexport interface LoadFromUrlOptions extends ImportGraphOptions {\n /**\n * Passed to fetch() as its second argument: headers, credentials, mode and so on. If you set\n * `signal` in the import options and not here, the same signal also cancels the download.\n */\n readonly request?: RequestInit | undefined;\n}\n\n/**\n * Options for downloadGraph(): the export options plus the name of the saved file.\n * @example\n * ```ts\n * await downloadGraph(snapshot, \"graphml\", { filename: \"network.graphml\" });\n * ```\n * @category Saving\n */\nexport interface DownloadGraphOptions extends ExportGraphOptions {\n /**\n * The file name the browser saves as. The default is \"graph\" plus the first entry of the\n * format's `extensions` (\"graph.graphml\"), or \"graph.<format>\" when it lists none.\n * @defaultValue \"graph\" plus the format's extension\n */\n readonly filename?: string | undefined;\n}\n\n/**\n * One format the registry can read, write or both.\n * @category Formats and detection\n */\nexport interface FormatInfo {\n /** The name you pass as `format`: \"graphml\", \"gexf\", \"csv\", \"pajek\", ... */\n readonly format: string;\n /**\n * File extensions with the leading dot, most common first (\".graphml\", \".net\"). Empty only for a\n * custom format that declares none.\n */\n readonly extensions: readonly string[];\n /** MIME types, most specific first. Empty when the format declares none. */\n readonly mimeTypes: readonly string[];\n /** Whether loadFromUrl(), loadFromFile() and importGraph() can read it. */\n readonly canImport: boolean;\n /** Whether the export functions can write it. */\n readonly canExport: boolean;\n /**\n * What the format can store exactly, or null when it cannot be written. The fields are\n * mixedDirection, multiEdges, selfLoops, edgeIds, idCharset, dtypes, components, lists, json,\n * defaults, options, hierarchy, temporal, graphAttributes, positions and viz (each documented on\n * ExportCapabilities). checkExport() tells you where a particular graph goes beyond this.\n */\n readonly capabilities: ExportCapabilities | null;\n}\n\n/**\n * The options of exportGraph(): the common export options plus any format-specific option, passed through.\n * @category Saving\n */\nexport interface ExportGraphOptions extends CommonExportOptions {\n /**\n * Write these styles too (`result.styles` of an import, or styles built for this graph): each element's look in\n * the format's own style slots and, where the format can keep them, the rules, so importing the file back\n * rebuilds them. What the format cannot hold is a W_STYLE_ note of checkExport(). Styles read from or built for a\n * different graph fail with E_STYLES_MISMATCH before anything is written.\n */\n readonly styles?: ExtractedStyles | null | undefined;\n /** Format-specific options, passed to the exporter as they are. */\n readonly [formatOption: string]: unknown;\n}\n\n/**\n * The options the load and save functions take themselves: the common import and export options and the functions'\n * own. With the formats' own `options` lists, these are the names a load or a save knows.\n */\nconst FUNCTION_OPTIONS: ReadonlySet<string> = new Set([\n \"addMissingNodes\",\n \"builder\",\n \"defaultDirected\",\n \"duplicateEdges\",\n \"encoding\",\n \"errorLimit\",\n \"filename\",\n \"format\",\n \"freeze\",\n \"graphIndex\",\n \"graphName\",\n \"hyperedges\",\n \"ids\",\n \"long\",\n \"maxEmptyCells\",\n \"mimeType\",\n \"nodeIdFrom\",\n \"onMixedDirection\",\n \"onProgress\",\n \"request\",\n \"restoreMangledIds\",\n \"sanitizeIds\",\n \"selfLoops\",\n \"signal\",\n \"styles\",\n \"weightDtype\",\n \"weightFrom\",\n]);\n\n/** The keys of ImportGraphOptions that belong to the registry, never to an importer. */\nconst REGISTRY_KEYS: ReadonlySet<string> = new Set([\n \"format\",\n \"filename\",\n \"mimeType\",\n \"builder\",\n \"freeze\",\n \"maxEmptyCells\",\n \"styles\",\n]);\n\n/**\n * A registry of importers and exporters by format name. Registration order is the tie-break\n * order of sniffing; the default registry lists the built-in formats in the\n * order of GRAPH_FORMATS.\n * @category Formats and detection\n */\nexport class FormatRegistry {\n private readonly importerMap = new Map<string, GraphImporter>();\n\n private readonly exporterMap = new Map<string, GraphExporter>();\n\n private readonly sources = new SourceRegistry(this, {\n newBuilder: (options, format) => seededBuilder(options as ImportGraphOptions, format),\n freeze: (format, builder, report, options) =>\n result(\n { importer: { format } as GraphImporter, sniff: null, source: \"\", peeked: null, warnings: [] },\n builder,\n report,\n options as ImportGraphOptions,\n ),\n });\n\n /**\n * Register a network source, or a lazy one whose code loads on first use. Source ids are their\n * own name space, apart from format names. Throws an ImportError with E_SOURCE_INVALID for a\n * malformed source or an id already taken. Experimental.\n * @param source - the source\n * @returns this registry\n */\n registerSource<P>(source: GraphSource<P> | LazySource): this {\n this.sources.register(source);\n return this;\n }\n\n /**\n * A registered source by id, its code loaded. Rejects with E_SOURCE_UNKNOWN for an id no\n * source has. Experimental.\n * @param id - the source id\n * @returns the source\n */\n source(id: string): Promise<GraphSource<never>> {\n return this.sources.resolve(id);\n }\n\n /**\n * Whether a source id is registered. Experimental.\n * @param id - the source id\n * @returns true when registered\n */\n hasSource(id: string): boolean {\n return this.sources.has(id);\n }\n\n /**\n * Every registered source with its descriptor, loading no source code. Experimental.\n * @returns one entry per source\n */\n listSources(): readonly SourceInfo[] {\n return this.sources.list();\n }\n\n /**\n * Load a graph from a network source; see the top-level loadFromSource(). Experimental.\n * @param source - the source id or the source\n * @param params - its params\n * @param options - endpoint, credential, cursor, caps and import options\n * @returns the graph and the report\n */\n loadFromSource(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n options?: LoadFromSourceOptions,\n ): Promise<ImportGraphResult> {\n return this.sources.load(source, params, options);\n }\n\n /**\n * Load from a network source into a sink you own. Experimental.\n * @param source - the source id or the source\n * @param params - its params\n * @param sink - where to write\n * @param options - the options\n * @returns the report\n */\n importFromSource(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n sink: GraphSink,\n options?: LoadFromSourceOptions,\n ): Promise<ImportReport> {\n return this.sources.import(source, params, sink, options);\n }\n\n /**\n * Fetch the neighborhood of some nodes from a network source. Experimental.\n * @param source - the source id or the source\n * @param request - the seeds and how far to go\n * @param options - the options\n * @returns a graph of only what was fetched\n */\n expandFromSource(\n source: string | GraphSource<never>,\n request: ExpandRequest<Readonly<Record<string, unknown>>>,\n options?: LoadFromSourceOptions,\n ): Promise<ImportGraphResult> {\n return this.sources.expand(source, request, options);\n }\n\n /**\n * Check a source's params and credential without loading. Experimental.\n * @param source - the source id or the source\n * @param params - its params\n * @param options - the options\n * @returns what the service said\n */\n probeSource(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n options?: LoadFromSourceOptions,\n ): Promise<SourceProbe> {\n return this.sources.probe(source, params, options);\n }\n\n /**\n * Search what a source holds. Experimental.\n * @param source - the source id or the source\n * @param query - the search\n * @param options - the options\n * @returns one page of results\n */\n listFromSource(\n source: string | GraphSource<never>,\n query: SourceListQuery<Readonly<Record<string, unknown>>>,\n options?: LoadFromSourceOptions,\n ): Promise<SourceListing> {\n return this.sources.search(source, query, options);\n }\n\n /**\n * Tell whether data loaded from a source changed. Experimental.\n * @param source - the source id or the source\n * @param params - the params it was loaded with\n * @param seen - the validators recorded then (`report.source.validators`)\n * @param options - the options\n * @returns whether it changed\n */\n validateSource(\n source: string | GraphSource<never>,\n params: Readonly<Record<string, unknown>>,\n seen: SourceValidators,\n options?: LoadFromSourceOptions,\n ): Promise<SourceFreshness> {\n return this.sources.validate(source, params, seen, options);\n }\n\n /**\n * Register an importer under its format name, replacing one of the same name in place (the\n * original registration order is kept).\n * @param importer - the importer\n * @returns this registry, for chaining\n */\n registerImporter(importer: GraphImporter): this {\n this.importerMap.set(importer.format, importer);\n return this;\n }\n\n /**\n * Register an exporter under its format name, replacing one of the same name.\n * @param exporter - the exporter\n * @returns this registry, for chaining\n */\n registerExporter(exporter: GraphExporter): this {\n this.exporterMap.set(exporter.format, exporter);\n return this;\n }\n\n /**\n * The importer of a format.\n * @param format - the format name\n * @returns the importer; E_UNSUPPORTED when none is registered\n */\n importer(format: FormatName): GraphImporter {\n const importer = this.importerMap.get(format);\n if (importer === undefined) {\n throw unknownFormat(\"importer\", format, this.importerMap.keys());\n }\n return importer;\n }\n\n /**\n * The exporter of a format.\n * @param format - the format name\n * @returns the exporter; E_UNSUPPORTED when none is registered\n */\n exporter(format: FormatName): GraphExporter {\n const exporter = this.exporterMap.get(format);\n if (exporter === undefined) {\n throw unknownFormat(\"exporter\", format, this.exporterMap.keys());\n }\n return exporter;\n }\n\n /**\n * Whether an importer is registered for a format.\n * @param format - the format name\n * @returns true when importer(format) would succeed\n */\n hasImporter(format: FormatName): boolean {\n return this.importerMap.has(format);\n }\n\n /**\n * Whether an exporter is registered for a format.\n * @param format - the format name\n * @returns true when exporter(format) would succeed\n */\n hasExporter(format: FormatName): boolean {\n return this.exporterMap.has(format);\n }\n\n /**\n * Every registered importer, in registration order.\n * @returns the importers\n */\n importers(): readonly GraphImporter[] {\n return [...this.importerMap.values()];\n }\n\n /**\n * Every registered exporter, in registration order.\n * @returns the exporters\n */\n exporters(): readonly GraphExporter[] {\n return [...this.exporterMap.values()];\n }\n\n /**\n * The names of every format with an importer or an exporter, importers' order first.\n * @returns the format names, each once\n */\n formats(): readonly string[] {\n return [...new Set([...this.importerMap.keys(), ...this.exporterMap.keys()])];\n }\n\n /**\n * Every format that could be the input, best first, from the same hints as sniff(): use it to\n * offer the user a choice when the best guess is not certain.\n * @param hints - `{ filename, mimeType, head }`, any of them\n * @returns the candidates, best first; empty when no format claims the input\n */\n sniffAll(hints: SniffHints): readonly SniffResult[] {\n return rankFormats(hints, this.importerMap.values());\n }\n\n /**\n * The best importer for an input, or null when no registered importer claims it.\n * @param hints - the filename, MIME type and / or head of the input\n * @returns the best candidate, or null\n */\n sniff(hints: SniffHints): SniffResult | null {\n const ranked = this.sniffAll(hints);\n return ranked.length > 0 ? ranked[0] : null;\n }\n\n /**\n * Read a graph from a string, bytes or a stream. The format is the one you name in `format`,\n * else it is detected from `filename`, `mimeType` and the first bytes of the content. From an\n * input that holds several graphs, it reads the one `graphIndex` or `graphName` chooses, else\n * the first, with a W_MULTIPLE_GRAPHS warning; importAllGraphs() returns every one.\n * @param input - the text, bytes, stream or chunks to read\n * @param options - the format, hints, common and format-specific import options\n * @returns the graph (`snapshot`), the format it was read as, and the import report\n */\n async importGraph(\n input: ImportInput,\n options: ImportGraphOptions | CommonImportOptions = {},\n ): Promise<ImportGraphResult> {\n const opts = options as ImportGraphOptions;\n const picked = await this.choose(input, opts);\n const unknown = this.unknownOptions(opts).map((name): ImportIssue =>\n Object.freeze({\n category: \"unsupported\",\n severity: \"warning\",\n code: UNKNOWN_OPTION_CODE,\n message: unknownOptionText(name),\n line: null,\n element: name,\n }),\n );\n const chosen = unknown.length === 0 ? picked : { ...picked, warnings: [...picked.warnings, ...unknown] };\n const { importer } = chosen;\n if (\n (opts.graphIndex !== undefined || opts.graphName !== undefined) &&\n importer.importAll !== undefined &&\n importer.listGraphs === undefined\n ) {\n // an importer that reads several graphs but does not choose among them itself (DOT, GML,\n // Pajek): read them all and return the chosen one, so the choice is never ignored\n const all = await this.readAll(chosen, opts);\n const names = all.map((r) => r.snapshot.meta.name);\n return all[chooseGraph(names, opts, new ImportReportBuilder(importer.format, 0))];\n }\n let builder: GraphBuilder;\n let report: ImportReport;\n try {\n builder = seededBuilder(opts, chosen.importer.format);\n report = await chosen.importer.import(chosen.source, builder, importerOptions(opts));\n } catch (err) {\n await chosen.peeked?.close();\n throw chosen.sniff === null ? notReadableAs(err, importer.format, opts.filename) : err;\n }\n return result(chosen, builder, report, opts);\n }\n\n /**\n * Fetch a graph file from a URL and load it; see the top-level loadFromUrl() for the full\n * description.\n * @param url - an absolute URL, or in a browser one relative to the page\n * @param options - import options, plus `request` for fetch\n * @returns the graph, the format it was read as, and the import report\n */\n async loadFromUrl(\n url: string | URL,\n options: LoadFromUrlOptions | CommonImportOptions = {},\n ): Promise<ImportGraphResult> {\n const opts = options as LoadFromUrlOptions;\n const { request, ...rest } = opts;\n const signal = request?.signal ?? rest.signal ?? null;\n const method = request?.method ?? \"GET\";\n const where = `${method} ${String(url)}`;\n let response: Response;\n try {\n response = await fetch(url, { signal: rest.signal, ...request });\n } catch (err) {\n if (signal?.aborted === true || isAbortError(err)) {\n throw err;\n }\n return fetchFailed(rest, url, `${where} failed: ${fetchErrorText(url, err)}`, null, err);\n }\n if (!response.ok) {\n await response.body?.cancel().catch(() => undefined);\n const status = `${String(response.status)} ${response.statusText}`.trim();\n return fetchFailed(rest, url, `${where} failed: ${status}`, response.status, null);\n }\n return this.importGraph(response.body ?? new Uint8Array(0), {\n ...rest,\n filename: rest.filename ?? urlFilename(url),\n mimeType: rest.mimeType ?? response.headers.get(\"content-type\"),\n });\n }\n\n /**\n * Load a graph from a File or Blob; see the top-level loadFromFile() for the full description.\n * @param file - the File or Blob to read\n * @param options - the same options as importGraph()\n * @returns the graph, the format it was read as, and the import report\n */\n loadFromFile(file: Blob, options: ImportGraphOptions | CommonImportOptions = {}): Promise<ImportGraphResult> {\n const opts = options as ImportGraphOptions;\n const { name } = file as { name?: unknown };\n return this.importGraph(file.stream(), {\n ...opts,\n filename: opts.filename ?? (typeof name === \"string\" ? name : null),\n mimeType: opts.mimeType ?? (file.type === \"\" ? null : file.type),\n });\n }\n\n /**\n * Read every graph of an input (a DOT file with several graphs, a Pajek project with several\n * networks, a JGF document with a `graphs` array), each as its own snapshot. A format that holds\n * one graph per file gives one result. Options and detection are those of importGraph().\n * @param input - the text, bytes, stream or chunks to read\n * @param options - the format, hints, common and format-specific import options\n * @returns one result per graph, in document order\n */\n async importAllGraphs(\n input: ImportInput,\n options: ImportGraphOptions | CommonImportOptions = {},\n ): Promise<ImportGraphResult[]> {\n const opts = options as ImportGraphOptions;\n return this.readAll(await this.choose(input, opts), opts);\n }\n\n /**\n * Read every graph of an input with the chosen importer.\n * @param chosen - the importer and the input to hand it\n * @param options - the importGraph options\n * @returns one result per graph, in document order\n */\n private async readAll(chosen: ChosenImporter, options: ImportGraphOptions): Promise<ImportGraphResult[]> {\n const { importer } = chosen;\n const builders: GraphBuilder[] = [];\n let reports: ImportReport[];\n try {\n if (importer.importAll === undefined) {\n builders.push(seededBuilder(options, importer.format));\n reports = [await importer.import(chosen.source, builders[0], importerOptions(options))];\n } else {\n reports = await importer.importAll(\n chosen.source,\n () => {\n const builder = seededBuilder(options, importer.format);\n builders.push(builder);\n return builder;\n },\n importerOptions(options),\n );\n }\n } catch (err) {\n await chosen.peeked?.close();\n throw inGraph(\n chosen.sniff === null ? notReadableAs(err, importer.format, options.filename) : err,\n builders.length - 1,\n );\n }\n return reports.map((report, i) => {\n try {\n return result(chosen, builders[i], report, options);\n } catch (err) {\n throw inGraph(err, i);\n }\n });\n }\n\n /**\n * The graphs of an input that can hold several, without importing them (a Cytoscape session's\n * networks, a JGF `graphs` array), so a caller can offer a choice and then pass `graphIndex`\n * or `graphName` to importGraph(). The format is named or sniffed as by importGraph().\n * @param input - the text, bytes, stream or chunks to read\n * @param options - the format, hints, common and format-specific import options\n * @returns one listing per graph, in document order; null when the format's importer does not\n * list its graphs (importGraph() then reads the first)\n */\n async listGraphs(\n input: ImportInput,\n options: ImportGraphOptions | CommonImportOptions = {},\n ): Promise<readonly GraphListing[] | null> {\n const opts = options as ImportGraphOptions;\n const chosen = await this.choose(input, opts);\n try {\n return chosen.importer.listGraphs === undefined\n ? null\n : await chosen.importer.listGraphs(chosen.source, importerOptions(opts));\n } finally {\n await chosen.peeked?.close();\n }\n }\n\n /**\n * The importer for an input: the named format, or the sniffed one.\n * @param rawInput - the input as the caller passed it\n * @param options - the importGraph options\n * @returns the importer, the sniff, and the input to read (replayed for a stream)\n */\n private async choose(rawInput: ImportInput, options: ImportGraphOptions): Promise<ChosenImporter> {\n const input = normalizeInput(rawInput);\n const requested = options.format ?? \"auto\";\n if (requested !== \"auto\") {\n return { importer: this.importer(requested), sniff: null, source: input, peeked: null, warnings: [] };\n }\n // the options are checked before the input is touched, so a bad option never leaves a\n // peeked stream locked; the importer resolves them again with its own defaults\n const common = resolveImportOptions(options, { ids: \"keep\", defaultDirected: true, weightFrom: null });\n maxEmptyCellsOption(options.maxEmptyCells);\n const peeked = await peekHead(input, SNIFF_HEAD_BYTES, common.signal);\n // the head is sniffed as the importer will read it: in the caller's encoding when given\n const head =\n common.encoding !== null && peeked.head instanceof Uint8Array\n ? new TextDecoder(common.encoding).decode(peeked.head, { stream: true })\n : peeked.head;\n let sniff: SniffResult | null;\n const failures = new ImportReportBuilder(\"unknown\", 0);\n const warnings: ImportIssue[] = [];\n try {\n const hints = { filename: options.filename, mimeType: options.mimeType, head };\n const ranked = rankFormats(hints, this.importerMap.values(), (format, err) => {\n warnings.push(\n failures.warning(\n \"unsupported\",\n SNIFF_FAILED_CODE,\n `the ${format} importer's sniff() threw (${messageOf(err)}); it was treated as not recognizing the input`,\n { element: format },\n ),\n );\n });\n sniff = ranked.length > 0 ? ranked[0] : null;\n } catch (err) {\n await peeked.close();\n throw err;\n }\n // a known non-graph file is refused whatever its name says, unless an importer claims its\n // content (a Cytoscape session is a zip); an HTML page always (the XML sniffers would\n // otherwise claim it by its markup)\n const foreign = foreignKind(peeked.head);\n const claimed = sniff !== null && sniff.content > 0 && !(foreign?.startsWith(\"an HTML\") ?? false);\n if (sniff === null || (foreign !== null && !claimed)) {\n await peeked.close();\n return this.refuseUndetected(failures, head, foreign, options);\n }\n return { importer: this.importer(sniff.format), sniff, source: peeked.input, peeked, warnings };\n }\n\n /**\n * Refuse an input no importer recognizes: empty, or not in a known graph format.\n * @param failures - the report the error is recorded in\n * @param head - the head, as sniffed\n * @param foreign - what known non-graph file the head is, or null\n * @param options - the importGraph options\n * @returns never: always throws\n */\n private refuseUndetected(\n failures: ImportReportBuilder,\n head: Uint8Array | string | null,\n foreign: string | null,\n options: ImportGraphOptions,\n ): never {\n const text = typeof head === \"string\" ? head : new TextDecoder().decode(head ?? new Uint8Array(0));\n if (text.trim() === \"\" && text.length < SNIFF_HEAD_BYTES) {\n // nothing to detect: say the input is empty, as a named format would\n return failures.fail(\n EMPTY_INPUT_CODE,\n text === \"\" ? \"the input is empty\" : \"the input holds only whitespace\",\n );\n }\n const what = foreign === null ? \"\" : `: it is ${foreign}`;\n return failures.fail(\n UNKNOWN_FORMAT_CODE,\n `the input is not in a graph format graph-io recognizes${describeHints(options)}${what}; if you know its format, pass it as the format option`,\n undefined,\n { formats: this.formats() },\n );\n }\n\n /**\n * Write a snapshot in a format, as UTF-8 chunks.\n * @param snapshot - the snapshot\n * @param format - the format name\n * @param options - the exporter's common and format-specific options\n * @returns the encoded chunks\n */\n exportGraph(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n ): AsyncIterable<Uint8Array> {\n const styled = this.styled(snapshot, format, options);\n if (styled === null) {\n return this.exporter(format).export(snapshot, options);\n }\n if (styled.refusal !== null) {\n return refuse(styled.refusal);\n }\n return styled.exporter.export(styled.snapshot, styled.options);\n }\n\n /**\n * An export with styles worked out, or null when no styles were given (the export is then exactly as before).\n * @param snapshot - the graph\n * @param format - the format name\n * @param options - the caller's options\n * @returns the exporter, the snapshot and options to hand it, the style losses and any refusal\n */\n private styled(\n snapshot: GraphSnapshot,\n format: FormatName,\n options: ExportGraphOptions | CommonExportOptions | undefined,\n ): StyledExport | null {\n const styles = (options as ExportGraphOptions | undefined)?.styles;\n if (styles === undefined || styles === null) {\n return null;\n }\n const exporter = this.exporter(format);\n const { styles: _given, ...rest } = options as ExportGraphOptions;\n const prepared = prepareStyleExport(snapshot, exporter, styles, rest);\n return {\n exporter,\n snapshot: prepared.snapshot,\n options: prepared.input === null ? rest : { ...rest, styles: prepared.input },\n plain: rest,\n notes: prepared.notes,\n refusal: prepared.refusal,\n };\n }\n\n /**\n * Write a snapshot in a format, as one string.\n * @param snapshot - the snapshot\n * @param format - the format name\n * @param options - the exporter's common and format-specific options\n * @returns the whole document\n */\n async exportGraphToString(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n ): Promise<string> {\n const styled = this.styled(snapshot, format, options);\n if (styled === null) {\n return this.exporter(format).exportToString(snapshot, options);\n }\n if (styled.refusal !== null) {\n throw refusalError(styled.refusal);\n }\n return styled.exporter.exportToString(styled.snapshot, styled.options);\n }\n\n /**\n * Write a snapshot in a format as one buffer of UTF-8 bytes; see the top-level\n * exportGraphToBytes().\n * @param snapshot - the graph to write\n * @param format - a format name where `canExport` is true\n * @param options - sanitizeIds, onMixedDirection and the format's own options\n * @returns the encoded file\n */\n exportGraphToBytes(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n ): Promise<Uint8Array> {\n return collectBytes(this.exportGraph(snapshot, format, options));\n }\n\n /**\n * Write a snapshot in a format as a Blob typed with the format's first MIME type; see the\n * top-level exportGraphToBlob().\n * @param snapshot - the graph to write\n * @param format - a format name where `canExport` is true\n * @param options - sanitizeIds, onMixedDirection and the format's own options\n * @returns the file as a Blob\n */\n async exportGraphToBlob(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n ): Promise<Blob> {\n const parts: Uint8Array[] = [];\n for await (const chunk of this.exportGraph(snapshot, format, options)) {\n parts.push(chunk);\n }\n const info = this.listFormats().find((f) => f.format === format);\n return new Blob(parts as BlobPart[], { type: info?.mimeTypes[0] ?? \"application/octet-stream\" });\n }\n\n /**\n * What exporting a snapshot in a format would lose, without writing anything.\n * @param snapshot - the snapshot\n * @param format - the format name\n * @param options - the exporter's common and format-specific options\n * @returns the loss notes, empty when the export is exact\n */\n checkExport(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n ): readonly LossNote[] {\n const styled = this.styled(snapshot, format, options);\n let notes: readonly LossNote[];\n if (styled === null) {\n notes = this.exporter(format).check(snapshot, options);\n } else if (styled.refusal === null) {\n // a property graph-io already reports as not written is reported once, whoever else notices\n const key = (n: LossNote): string =>\n `${n.code}\\u0000${n.style?.target ?? \"\"}\\u0000${n.style?.property ?? \"\"}`;\n const reported = new Set(styled.notes.filter((n) => n.style !== undefined).map(key));\n notes = [\n ...styled.exporter\n .check(styled.snapshot, styled.options)\n .filter(\n (n) =>\n n.style === undefined ||\n (!reported.has(key(n)) && !isKeptGraphtyProperty(n, styled.exporter)),\n ),\n ...styled.notes,\n ];\n } else {\n notes = [...styled.exporter.check(snapshot, styled.plain), styled.refusal];\n }\n const unknown = this.unknownOptions(options);\n if (unknown.length === 0) {\n return notes;\n }\n return Object.freeze([\n ...notes,\n ...unknown.map((name) =>\n Object.freeze({\n code: UNKNOWN_OPTION_CODE,\n message: unknownOptionText(name),\n column: null,\n count: null,\n }),\n ),\n ]);\n }\n\n /**\n * The option names no registered format and no load or save function takes (misspellings), or none while a\n * registered format does not list its options.\n * @param options - the caller's options\n * @returns the unknown names\n */\n private unknownOptions(options: object | null | undefined): string[] {\n if (options === null || options === undefined) {\n return [];\n }\n const known = new Set(FUNCTION_OPTIONS);\n for (const plugin of [...this.importerMap.values(), ...this.exporterMap.values()]) {\n if (plugin.options === undefined) {\n return [];\n }\n for (const name of plugin.options) {\n known.add(name);\n }\n }\n return Object.entries(options)\n .filter(([name, value]) => value !== undefined && !known.has(name))\n .map(([name]) => name);\n }\n\n /**\n * Browser only: write a graph in a format and have the browser save it as a file; see the\n * top-level downloadGraph(). Use this method on a registry from createRegistry() to download\n * without bundling every built-in format.\n * @param snapshot - the graph to write\n * @param format - a format name from listFormats() where `canExport` is true\n * @param options - the export options, plus `filename`\n * @returns resolves once the download has been handed to the browser\n */\n async downloadGraph(\n snapshot: GraphSnapshot,\n format: FormatName,\n options: DownloadGraphOptions | CommonExportOptions = {},\n ): Promise<void> {\n if (typeof document === \"undefined\") {\n throw new GraphFormatError(\n \"E_UNSUPPORTED\",\n \"downloadGraph() needs a browser document; use exportGraphToBytes() and write the bytes yourself\",\n );\n }\n const { filename, ...rest } = options as DownloadGraphOptions;\n const blob = await this.exportGraphToBlob(snapshot, format, rest);\n const extension = this.listFormats().find((f) => f.format === format)?.extensions[0] ?? `.${format}`;\n const href = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = href;\n anchor.download = filename ?? `graph${extension}`;\n anchor.click();\n // Safari cancels the download when the URL is revoked in the same task\n setTimeout(() => {\n URL.revokeObjectURL(href);\n }, 0);\n }\n\n /**\n * Every format this registry can read or write, in registration order; see the top-level\n * listFormats().\n * @returns one entry per format\n */\n listFormats(): readonly FormatInfo[] {\n return this.formats().map((format) => {\n const importer = this.importerMap.get(format);\n const exporter = this.exporterMap.get(format);\n return Object.freeze({\n format,\n extensions: importer?.extensions ?? exporter?.extensions ?? [],\n mimeTypes: importer?.mimeTypes ?? exporter?.mimeTypes ?? [],\n canImport: importer !== undefined,\n canExport: exporter !== undefined,\n capabilities: capabilitiesOf(exporter),\n });\n });\n }\n}\n\n/**\n * A new registry holding every built-in importer and exporter, in the order of GRAPH_FORMATS.\n * @returns a new registry\n * @category Formats and detection\n */\nexport function createRegistry(): FormatRegistry {\n const formats = new FormatRegistry()\n .registerImporter(jsonImporter)\n .registerExporter(jsonExporter)\n .registerImporter(graphmlImporter)\n .registerExporter(graphmlExporter)\n .registerImporter(gexfImporter)\n .registerExporter(gexfExporter)\n .registerImporter(csvImporter)\n .registerExporter(csvExporter)\n .registerImporter(gmlImporter)\n .registerExporter(gmlExporter)\n .registerImporter(dotImporter)\n .registerExporter(dotExporter)\n .registerImporter(pajekImporter)\n .registerExporter(pajekExporter)\n .registerImporter(neo4jImporter)\n .registerExporter(neo4jExporter)\n .registerImporter(xgmmlImporter)\n .registerExporter(xgmmlExporter)\n .registerImporter(cx2Importer)\n .registerExporter(cx2Exporter)\n .registerImporter(cxImporter)\n .registerExporter(cxExporter)\n .registerImporter(oboImporter)\n .registerExporter(oboExporter)\n .registerImporter(cysImporter)\n .registerExporter(cysExporter);\n for (const source of builtinSources()) {\n formats.registerSource(source);\n }\n return formats;\n}\n\n/**\n * The default registry: every built-in format.\n * @category Formats and detection\n */\nexport const registry: FormatRegistry = /* @__PURE__ */ createRegistry();\n\n/**\n * Read a graph from a string, bytes or a stream. The format is the one you name in `format`, else\n * it is detected from `filename`, `mimeType` and the first bytes; an input that matches no format\n * fails with E_UNKNOWN_FORMAT. From a file that holds several graphs it reads the one `graphIndex`\n * or `graphName` chooses, else the first, with a W_MULTIPLE_GRAPHS warning. For a File or Blob use\n * loadFromFile(), for a URL loadFromUrl().\n * @param input - the whole text, the bytes (a Uint8Array or a Node Buffer), a ReadableStream of\n * bytes, or an async iterable of text or byte chunks (a Node read stream)\n * @param options - the format, format hints, the options every importer takes and the format's own\n * options\n * @returns the graph (`snapshot`), the format it was read as, and the import report\n * @throws ImportError when the input could not be read; `err.issue?.code` says why\n * @throws GraphFormatError with code E_UNSUPPORTED for a `format` no importer is registered for, or\n * an option value that is not allowed (`err.details.option` names it)\n * @throws the signal's reason when `signal` aborts\n * @category Loading\n */\nexport function importGraph(\n input: ImportInput,\n options?: ImportGraphOptions | CommonImportOptions,\n): Promise<ImportGraphResult> {\n return registry.importGraph(input, options);\n}\n\n/**\n * Read every graph of a file that can hold several (DOT, GML, a Pajek project, a JSON Graph Format\n * or OBO Graphs document, CX, XGMML, a Cytoscape session). A format that holds one graph per file\n * gives one result. Options and errors are the same as importGraph()'s.\n * @param input - the text, bytes or stream to read\n * @param options - the same options as importGraph()\n * @returns one result per graph, in file order\n * @category Loading\n */\nexport function importAllGraphs(\n input: ImportInput,\n options?: ImportGraphOptions | CommonImportOptions,\n): Promise<ImportGraphResult[]> {\n return registry.importAllGraphs(input, options);\n}\n\n/**\n * List the graphs of a file without reading them: each one's `index`, `name`, and node and edge\n * counts when the file states them. Pass the index or name to importGraph() as `graphIndex` or\n * `graphName`. The counts come from the file and can differ from what an import reads, for example\n * when the import adds edges the listing does not count. JSON, CX, XGMML and Cytoscape sessions can\n * list their graphs; for DOT, GML and Pajek it returns null, and importAllGraphs() is the way to see\n * them.\n * @param input - the text, bytes or stream to read\n * @param options - the same options as importGraph()\n * @returns one listing per graph, in file order; null when the format cannot list its graphs\n * @category Loading\n */\nexport function listGraphs(\n input: ImportInput,\n options?: ImportGraphOptions | CommonImportOptions,\n): Promise<readonly GraphListing[] | null> {\n return registry.listGraphs(input, options);\n}\n\n/**\n * Write a graph in a format as a stream of UTF-8 byte chunks, for a graph too large to hold as one\n * file in memory. In Node, pipe it to a file with `pipeline(exportGraph(...), createWriteStream(path))`.\n * Options and errors are the same as exportGraphToBytes()'s.\n * @param snapshot - the graph to write\n * @param format - a format name from listFormats() where `canExport` is true\n * @param options - sanitizeIds, onMixedDirection and the format's own options\n * @returns the file's bytes, chunk by chunk\n * @category Saving\n */\nexport function exportGraph(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n): AsyncIterable<Uint8Array> {\n return registry.exportGraph(snapshot, format, options);\n}\n\n/**\n * Write a graph in a format and return the file as one string. A binary format (a Cytoscape\n * session) cannot be a string and fails with E_UNSUPPORTED; use exportGraphToBytes() for it. Options\n * and errors are the same as exportGraphToBytes()'s.\n * @param snapshot - the graph to write\n * @param format - a format name from listFormats() where `canExport` is true\n * @param options - sanitizeIds, onMixedDirection and the format's own options\n * @returns the whole file\n * @category Saving\n */\nexport async function exportGraphToString(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n): Promise<string> {\n return registry.exportGraphToString(snapshot, format, options);\n}\n\n/**\n * What saving a graph in a format would lose, without writing anything. Pass the same options you\n * will pass to the save. Each note has a stable `code`: \"E_\" means the save would throw, \"W_\" means\n * the file is written but that part does not read back the same. An empty array means the file\n * reads back as the same graph. Runs synchronously.\n * @param snapshot - the graph to check\n * @param format - a format name from listFormats() where `canExport` is true\n * @param options - the options you will save with\n * @returns the loss notes, empty when the save is exact\n * @throws GraphFormatError with code E_UNSUPPORTED when no exporter is registered for `format`, or\n * when an option value is not allowed (`err.details.option` names it)\n * @category Saving\n */\nexport function checkExport(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n): readonly LossNote[] {\n return registry.checkExport(snapshot, format, options);\n}\n\n/**\n * Fetch a graph file from a URL and load it. The file is streamed into the importer as it\n * downloads, so a large file is not held in memory twice. When you do not name a `format`, it is\n * worked out from the URL's file name, the response's Content-Type and the first bytes of the\n * file. Your own `filename` or `mimeType` option takes the place of the hint from the URL or the\n * response. Every other option goes to importGraph() unchanged, including format-specific ones\n * such as `delimiter` or `dialect`, and `graphIndex` / `graphName` for files that hold several\n * graphs. The result is the same as importGraph()'s. A successful load can still have skipped\n * elements; check `report.errorCount` and `report.warningCount`, or pass `errorLimit: 0` to make\n * the first error fatal. Works wherever fetch exists: browsers, Node 18 and later, Deno, Bun and\n * workers.\n * @param url - an absolute URL, or in a browser one relative to the page\n * @param options - import options, plus `request` for fetch\n * @returns the graph, the format it was read as, and the import report\n * @throws ImportError when the file could not be loaded; `err.issue?.code` is \"E_FETCH\" for a\n * network failure, a CORS refusal or a status outside 200-299 (`err.details.url`,\n * `err.details.status` -- null for a network failure -- and `err.details.cause`, fetch's own\n * error), \"E_UNKNOWN_FORMAT\" when no format recognizes the file (pass `format`), or the code of\n * the parse error\n * @throws GraphFormatError with code E_UNSUPPORTED when `format` names no registered importer\n * @throws the signal's reason when `signal` aborts\n * @example\n * ```ts\n * import { GraphFormatError, loadFromUrl } from \"@graphty/graph-io\";\n *\n * try {\n * const { snapshot, format } = await loadFromUrl(\"https://example.com/data/karate.gml\");\n * console.log(`${format}: ${snapshot.nodeCount} nodes, ${snapshot.edgeCount} edges`);\n * } catch (err) {\n * if (err instanceof GraphFormatError) {\n * console.error(err.message);\n * } else {\n * throw err;\n * }\n * }\n * ```\n * @category Loading\n */\nexport function loadFromUrl(\n url: string | URL,\n options?: LoadFromUrlOptions | CommonImportOptions,\n): Promise<ImportGraphResult> {\n return registry.loadFromUrl(url, options);\n}\n\n/**\n * Load a graph from a File or Blob: a file the user picked in an `<input type=\"file\">`, a file\n * dropped on the page, a Blob you built, or in Node a Blob from `fs.openAsBlob(path)`. The content\n * is streamed into the importer. A File's `name` and the Blob's `type` are used as format hints\n * unless you pass `filename` or `mimeType` yourself. Options, result and errors are the same as\n * loadFromUrl()'s, without E_FETCH.\n * @param file - the File or Blob to read\n * @param options - the same options as importGraph()\n * @returns the graph, the format it was read as, and the import report\n * @throws ImportError when the file could not be loaded (`err.issue?.code` E_UNKNOWN_FORMAT or a parse error)\n * @throws GraphFormatError with code E_UNSUPPORTED when `format` names no registered importer\n * @throws the signal's reason when `signal` aborts\n * @example\n * ```ts\n * input.addEventListener(\"change\", async () => {\n * const file = input.files?.[0];\n * if (file) {\n * const { snapshot, report } = await loadFromFile(file);\n * console.log(`${snapshot.nodeCount} nodes, ${report.errorCount} skipped`);\n * }\n * });\n * ```\n * @category Loading\n */\nexport function loadFromFile(\n file: Blob,\n options?: ImportGraphOptions | CommonImportOptions,\n): Promise<ImportGraphResult> {\n return registry.loadFromFile(file, options);\n}\n\n/**\n * Write a graph in a format and return the whole file as UTF-8 bytes, ready for fs.writeFile, a\n * fetch body or a zip entry. Prefer this over exportGraphToString() when the result goes to a file\n * or the network. To stream a very large graph, use exportGraph(). To find out beforehand what the\n * file will not keep, call checkExport() with the same format and the same options object: every\n * \"E_\" note it returns makes this call throw, and every \"W_\" note describes a loss this call\n * accepts. Most \"E_\" notes go away with `sanitizeIds: \"mangle\"` (rewrite ids the format cannot\n * hold) or `onMixedDirection: \"directed\"` / `\"undirected\"`. The format's own options (the CSV\n * `table` and `dialect`, the GEXF `version`, ...) go in the same object.\n * @param snapshot - the graph to write\n * @param format - a format name from listFormats() where `canExport` is true\n * @param options - sanitizeIds, onMixedDirection and the format's own options\n * @returns the encoded file\n * @throws GraphFormatError with code E_UNSUPPORTED when no exporter is registered for `format`\n * @throws GraphFormatError when the graph cannot be written in this format under these options\n * (checkExport() returns an \"E_\" note for the same call). The thrown code names the kind of\n * failure rather than the note: E_INVALID_ID for ids (the E_ID_CHARSET and E_ID_TEXT_COLLISION\n * notes), E_DIRECTED for direction (E_MIXED_DIRECTION), and E_COLUMN_TYPE or E_UNSUPPORTED for a\n * value the format cannot write; each note's entry on the codes page says which\n * @throws GraphFormatError with code E_UNSUPPORTED for an option value that is not allowed\n * (`err.details.option` names it)\n * @example\n * ```ts\n * import { writeFile } from \"node:fs/promises\";\n *\n * await writeFile(\"out.gexf\", await exportGraphToBytes(snapshot, \"gexf\"));\n * ```\n * @category Saving\n */\nexport function exportGraphToBytes(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n): Promise<Uint8Array> {\n return registry.exportGraphToBytes(snapshot, format, options);\n}\n\n/**\n * Write a graph in a format and return it as a Blob, for uploading with fetch or FormData or for\n * offering as a download. The Blob's `type` is the first entry of the format's `mimeTypes` in\n * listFormats(), or application/octet-stream when the format lists none. The exporter's chunks\n * are kept as they are and never joined into one string. Options and errors are the same as\n * exportGraphToBytes().\n * @param snapshot - the graph to write\n * @param format - a format name from listFormats() where `canExport` is true\n * @param options - sanitizeIds, onMixedDirection and the format's own options\n * @returns the file as a Blob\n * @throws the same errors as exportGraphToBytes()\n * @example\n * ```ts\n * const body = new FormData();\n * body.append(\"file\", await exportGraphToBlob(snapshot, \"graphml\"), \"graph.graphml\");\n * await fetch(\"/api/graphs\", { method: \"POST\", body });\n * ```\n * @category Saving\n */\nexport function exportGraphToBlob(\n snapshot: GraphSnapshot,\n format: FormatName,\n options?: ExportGraphOptions | CommonExportOptions,\n): Promise<Blob> {\n return registry.exportGraphToBlob(snapshot, format, options);\n}\n\n/**\n * Browser only: write a graph in a format and have the browser save it as a file, the same as\n * clicking a download link. Call it from a click handler; awaiting other work first is fine. The\n * promise resolves once the file has been handed to the browser. There is no way to learn\n * whether the user then canceled the save. Calling it where there is no `document` (Node, a\n * worker) throws instead of silently doing nothing; importing it is safe everywhere. Formats you\n * registered with `registry.registerExporter()` can be downloaded too.\n * @param snapshot - the graph to write\n * @param format - a format name from listFormats() where `canExport` is true\n * @param options - the export options, plus `filename`\n * @returns resolves once the download has been handed to the browser\n * @throws GraphFormatError with code E_UNSUPPORTED when called without a DOM `document`\n * @throws the same errors as exportGraphToBytes()\n * @example\n * ```ts\n * saveButton.addEventListener(\"click\", () => {\n * void downloadGraph(snapshot, \"graphml\", { filename: \"network.graphml\" });\n * });\n * ```\n * @category Saving\n */\nexport async function downloadGraph(\n snapshot: GraphSnapshot,\n format: FormatName,\n options: DownloadGraphOptions | CommonExportOptions = {},\n): Promise<void> {\n return registry.downloadGraph(snapshot, format, options);\n}\n\n/**\n * Every format the default registry can read or write, including any you registered yourself:\n * the built-in formats in the order of GRAPH_FORMATS (the order format detection prefers them),\n * then yours in registration order. Use it to fill a \"Save as\" menu (the entries with\n * `canExport`), a file input's `accept` attribute (the `extensions` of the entries with\n * `canImport`), or to pick the output format from a file name.\n * @returns one entry per format\n * @example\n * ```ts\n * input.accept = listFormats().filter((f) => f.canImport).flatMap((f) => f.extensions).join(\",\");\n * const target = listFormats().find((f) => f.canExport && f.extensions.includes(extensionOf(path) ?? \"\"));\n * ```\n * @category Formats and detection\n */\nexport function listFormats(): readonly FormatInfo[] {\n return registry.listFormats();\n}\n\n/**\n * Detect a file's format without reading it, from what you know about it: a `filename` (only the\n * extension counts), a `mimeType`, and `head`, the file's first bytes or characters (up to\n * SNIFF_HEAD_BYTES; pass `bytes.subarray(0, SNIFF_HEAD_BYTES)`). It uses every format of the default\n * registry, including the ones you registered. For every candidate, best first, call\n * `registry.sniffAll(hints)`.\n * @param hints - `{ filename, mimeType, head }`, any of them\n * @returns the best candidate (`format`, `confidence` and what matched), or null when no format\n * claims the input\n * @example\n * ```ts\n * sniff({ filename: \"graph.xml\", head: \"<?xml version=\\\"1.0\\\"?><gexf\" })?.format; // \"gexf\"\n * ```\n * @category Formats and detection\n */\nexport function sniff(hints: SniffHints): SniffResult | null {\n return registry.sniff(hints);\n}\n\n/**\n * Abort a loadFromUrl() whose fetch failed with an E_FETCH ImportError.\n * @param options - the import options (for the format name on the report)\n * @param url - the URL\n * @param message - the message\n * @param status - the HTTP status, or null for a network failure\n * @param cause - fetch's own error, or null\n * @returns never; always throws\n */\nfunction fetchFailed(\n options: ImportGraphOptions,\n url: string | URL,\n message: string,\n status: number | null,\n cause: unknown,\n): never {\n const format = options.format === undefined || options.format === \"auto\" ? \"unknown\" : options.format;\n return new ImportReportBuilder(format, 0).fail(FETCH_CODE, message, undefined, { url: String(url), status, cause });\n}\n\n/**\n * The error for an input refused by the format the caller named before any element was read: the\n * parser's message (\"line 1: text outside the root element\") prefixed with the file and the format,\n * since the likely cause is a file of another kind, not a damaged one.\n * @param err - what the importer threw\n * @param format - the format named in `format`\n * @param filename - the file name hint, if any\n * @returns the error to throw\n */\nfunction notReadableAs(err: unknown, format: string, filename: string | null | undefined): unknown {\n if (\n !(err instanceof ImportError) ||\n err.issue?.category !== \"parse-error\" ||\n err.report.errorCount > 1 ||\n err.report.counts.nodes + err.report.counts.edges > 0\n ) {\n return err;\n }\n const what = filename === undefined || filename === null ? \"the input\" : JSON.stringify(filename);\n return new ImportError(`${what} could not be read as ${format}: ${err.message}`, err.report, err.details);\n}\n\n/**\n * Why fetch() rejected, in words that point at the fix: a relative URL with no page to resolve it\n * against (Node), a file: URL fetch() does not read, or a network error, which in a browser\n * includes a CORS refusal.\n * @param url - the URL as given\n * @param err - what fetch() threw\n * @returns the reason\n */\nfunction fetchErrorText(url: string | URL, err: unknown): string {\n let absolute: URL | null = null;\n try {\n absolute = new URL(url);\n } catch {\n // relative: resolvable only against a page's location\n }\n if (absolute === null && (globalThis as { location?: unknown }).location === undefined) {\n return \"a relative URL needs a web page to resolve against; outside a browser pass an absolute http(s) URL, or read a local file with loadFromFile() or importGraph()\";\n }\n if (absolute?.protocol === \"file:\") {\n return \"fetch() cannot read file: URLs here; read a local file with loadFromFile() or importGraph()\";\n }\n const cause = (err as { cause?: { message?: unknown } } | null)?.cause?.message;\n const detail = typeof cause === \"string\" && cause !== \"\" ? ` (${cause})` : \"\";\n return `the server could not be reached, or (in a browser) it does not allow this page to read the file (CORS)${detail}`;\n}\n\n/**\n * The last path segment of a URL, as a format hint.\n * @param url - the URL, absolute or relative\n * @returns the file name, or null when the path ends in \"/\"\n */\nfunction urlFilename(url: string | URL): string | null {\n const path = new URL(url, \"http://localhost/\").pathname;\n const name = path.slice(path.lastIndexOf(\"/\") + 1);\n return name === \"\" ? null : name;\n}\n\n/**\n * The options handed to the importer: everything but the registry's own keys.\n * @param options - the importGraph options\n * @returns the importer's options\n */\nfunction importerOptions(options: ImportGraphOptions): CommonImportOptions {\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(options)) {\n if (!REGISTRY_KEYS.has(key)) {\n out[key] = value;\n }\n }\n return out;\n}\n\n/** The importer chosen for an input, and the input to hand it. */\ninterface ChosenImporter {\n /** The importer. */\n readonly importer: GraphImporter;\n /** The sniff that chose it, or null when the caller named the format. */\n readonly sniff: SniffResult | null;\n /** The input to read: the original, or a replaying iterable for a peeked stream. */\n readonly source: ImportInput;\n /** The peeked head of a sniffed input, or null. */\n readonly peeked: PeekedInput | null;\n /** W_SNIFF_FAILED warnings for the import report, one per importer whose sniff() threw. */\n readonly warnings: readonly ImportIssue[];\n}\n\n/**\n * A fresh builder seeded from the common options, `directed: true` as a placeholder the importer\n * overrides from the file, that stops the import when its attributes get too sparse.\n * @param options - the importGraph options\n * @param format - the format being read\n * @returns the builder\n */\nfunction seededBuilder(options: ImportGraphOptions, format: string): GraphBuilder {\n const maxEmptyCells = maxEmptyCellsOption(options.maxEmptyCells);\n try {\n return newBuilder(options, format, maxEmptyCells);\n } catch (err) {\n // the builder names a bad value by its field; report it as the option the caller passed\n if (err instanceof GraphFormatError && err.code === \"E_UNSUPPORTED\" && typeof err.details.field === \"string\") {\n const option = err.details.field;\n throw new GraphFormatError(\n \"E_UNSUPPORTED\",\n `option ${option}: ${JSON.stringify(err.details.found)} is not one of the values it takes`,\n { option, found: err.details.found },\n );\n }\n throw err;\n }\n}\n\n/**\n * The builder of seededBuilder(), before its option errors are reworded.\n * @param options - the importGraph options\n * @param format - the format being read\n * @param maxEmptyCells - the empty-cell budget\n * @returns the builder\n */\nfunction newBuilder(options: ImportGraphOptions, format: string, maxEmptyCells: number): GraphBuilder {\n return new CellBudgetBuilder(\n {\n weightDtype: options.weightDtype ?? \"f64\",\n ...options.builder,\n directed: true,\n addMissingNodes: options.addMissingNodes ?? true,\n duplicateEdges: options.duplicateEdges ?? \"keep\",\n selfLoops: options.selfLoops ?? \"keep\",\n },\n format,\n maxEmptyCells,\n );\n}\n\n/**\n * Name the graph an importAllGraphs() failure belongs to: the report is that graph's own, so the\n * message is prefixed with its index and `details.graphIndex` set, for every graph including the\n * first. Anything other than an ImportError raised while a graph was being read passes unchanged.\n * @param err - the error thrown while reading or freezing a graph\n * @param index - the index of that graph, -1 before the first graph began\n * @returns the error to throw\n */\nfunction inGraph(err: unknown, index: number): unknown {\n if (!(err instanceof ImportError) || index < 0) {\n return err;\n }\n return new ImportError(`graph ${index}: ${err.message}`, err.report, { ...err.details, graphIndex: index });\n}\n\n/**\n * Freeze an imported builder into an importGraph result.\n * @param chosen - the importer and its sniff\n * @param builder - the filled builder\n * @param report - the importer's report\n * @param options - the importGraph options\n * @returns the frozen result\n */\nfunction result(\n chosen: ChosenImporter,\n builder: GraphBuilder,\n report: ImportReport,\n options: ImportGraphOptions,\n): ImportGraphResult {\n let frozen: ReturnType<GraphBuilder[\"freezeWithReport\"]>;\n try {\n frozen = builder.freezeWithReport(options.freeze);\n } catch (err) {\n throw freezeFailure(err, report);\n }\n const { warnings } = chosen;\n const wanted = options.styles;\n let styles: ExtractedStyles | null | undefined;\n if (wanted !== undefined && wanted !== false) {\n styles = extractStyles(chosen.importer, frozen.snapshot, report, {\n signal: options.signal,\n toolDefaults: typeof wanted === \"object\" ? wanted.toolDefaults : undefined,\n });\n }\n const read =\n styles !== undefined && chosen.importer.styles !== undefined ? withoutStylesNotImported(report) : report;\n const result = {\n format: chosen.importer.format,\n sniff: chosen.sniff,\n snapshot: frozen.snapshot,\n report: withFreezeWarnings(\n weightNotFound(\n warnings.length === 0\n ? read\n : Object.freeze({\n ...read,\n issues: Object.freeze([...warnings, ...read.issues]),\n warningCount: read.warningCount + warnings.length,\n }),\n frozen.snapshot,\n options.weightFrom,\n ),\n frozen.report,\n ),\n };\n if (styles !== undefined) {\n Object.assign(result, { styles });\n }\n // not enumerable: it holds one entry per edge, and console.log(result) should show the graph, not that\n Object.defineProperty(result, \"freeze\", { value: frozen.report, enumerable: false });\n return Object.freeze(result as ImportGraphResult);\n}\n\n/**\n * A report without its W_STYLES_NOT_IMPORTED warnings: the importer read the styles it would have named.\n * @param report - the importer's report\n * @returns the report, a copy only when it held such a warning\n */\nfunction withoutStylesNotImported(report: ImportReport): ImportReport {\n const issues = report.issues.filter((i) => i.code !== STYLES_NOT_IMPORTED_CODE);\n if (issues.length === report.issues.length) {\n return report;\n }\n return Object.freeze({\n ...report,\n issues: Object.freeze(issues),\n warningCount: report.warningCount - (report.issues.length - issues.length),\n });\n}\n\n/** An export with styles, worked out by FormatRegistry.styled(). */\ninterface StyledExport {\n /** The exporter. */\n readonly exporter: GraphExporter;\n /** The snapshot to hand it. */\n readonly snapshot: GraphSnapshot;\n /** The options to hand it: the caller's, with `styles` replaced by the exporter's input or left out. */\n readonly options: ExportGraphOptions;\n /** The caller's options without `styles`. */\n readonly plain: ExportGraphOptions;\n /** The style losses. */\n readonly notes: readonly LossNote[];\n /** E_STYLES_MISMATCH, or null. */\n readonly refusal: LossNote | null;\n}\n\n/**\n * The error an export refused for its styles throws.\n * @param note - the refusal note\n * @returns the error\n */\nfunction refusalError(note: LossNote): GraphFormatError {\n return new GraphFormatError(\"E_UNSUPPORTED\", note.message, { code: note.code });\n}\n\n/**\n * Chunks that fail on the first read, before any byte: an export refused for its styles.\n * @param note - the refusal note\n * @returns chunks whose first read rejects\n */\nfunction refuse(note: LossNote): AsyncIterable<Uint8Array> {\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(refusalError(note)) }),\n };\n}\n\n/**\n * The capabilities listFormats() reports for an exporter: its table plus, when it writes styles, their capabilities.\n * @param exporter - the exporter, or undefined\n * @returns the capabilities, or null\n */\nfunction capabilitiesOf(exporter: GraphExporter | undefined): ExportCapabilities | null {\n if (exporter === undefined) {\n return null;\n }\n if (exporter.styles === undefined) {\n return exporter.capabilities;\n }\n return Object.freeze({ ...exporter.capabilities, styles: exporter.styles.capabilities });\n}\n\n/**\n * The message of a W_UNKNOWN_OPTION warning or note.\n * @param name - the option name\n * @returns the message\n */\nfunction unknownOptionText(name: string): string {\n return `option ${JSON.stringify(name)} is not an option of any format or of the load and save functions, so it has no effect; check its spelling`;\n}\n\n/**\n * The import report with one W_WEIGHT_NOT_FOUND warning when the caller's `weightFrom` named an attribute that gave\n * no edge a weight, so a name that misses (a shared options object read against GML's `value`) is not silent. A\n * format that does not read `weightFrom` already reported it as W_OPTION_IGNORED.\n * @param report - the import's report\n * @param snapshot - the graph read\n * @param weightFrom - the caller's option\n * @returns the report, with the warning added when it applies\n */\nfunction weightNotFound(report: ImportReport, snapshot: GraphSnapshot, weightFrom: unknown): ImportReport {\n if (\n typeof weightFrom !== \"string\" ||\n snapshot.edgeCount === 0 ||\n snapshot.edgeList().weights !== null ||\n report.issues.some((i) => i.code === OPTION_IGNORED_CODE && i.element === \"weightFrom\")\n ) {\n return report;\n }\n const issue: ImportIssue = Object.freeze({\n category: \"missing-value\",\n severity: \"warning\",\n code: WEIGHT_NOT_FOUND_CODE,\n message: `weightFrom: ${JSON.stringify(weightFrom)} names no attribute an edge has a value for, so the graph has no weights`,\n line: null,\n element: \"weightFrom\",\n });\n return Object.freeze({\n ...report,\n issues: Object.freeze([...report.issues, issue]),\n warningCount: report.warningCount + 1,\n });\n}\n\n/**\n * The import report with what the builder's policies changed while the graph was built: one\n * W_EDGES_MERGED warning when `duplicateEdges` merged parallel edges (whatever told them apart, a\n * relation or a label, is lost) and one W_SELF_LOOPS_DROPPED warning when `selfLoops: \"drop\"`\n * removed self-loops, so nothing the caller's options removed goes unreported.\n * @param report - the import's report\n * @param freeze - the freeze report\n * @returns the report, with the warnings added\n */\nfunction withFreezeWarnings(report: ImportReport, freeze: FreezeReport): ImportReport {\n const added: ImportIssue[] = [];\n const warn = (category: IssueCategory, code: string, message: string): void => {\n added.push(Object.freeze({ category, severity: \"warning\" as const, code, message, line: null, element: null }));\n };\n if (freeze.mergedEdges > 0) {\n warn(\n \"merged\",\n EDGES_MERGED_CODE,\n `${freeze.mergedEdges} parallel edge${plural(freeze.mergedEdges)} ${agree(freeze.mergedEdges, \"was\", \"were\")} merged into one edge per pair by the duplicateEdges policy; whatever told them apart (a relation, a label) is lost`,\n );\n }\n if (freeze.droppedSelfLoops > 0) {\n warn(\n \"validation-error\",\n SELF_LOOPS_DROPPED_CODE,\n `${freeze.droppedSelfLoops} self-loop${plural(freeze.droppedSelfLoops)} ${agree(freeze.droppedSelfLoops, \"was\", \"were\")} removed by selfLoops: \"drop\"`,\n );\n }\n if (added.length === 0) {\n return report;\n }\n return Object.freeze({\n ...report,\n issues: Object.freeze([...report.issues, ...added]),\n warningCount: report.warningCount + added.length,\n });\n}\n\n/**\n * The ImportError of a freeze the builder refused (a `duplicateEdges: \"error\"` or `selfLoops:\n * \"error\"` policy meeting a duplicate edge or a self-loop the file holds): the builder's code\n * recorded as an error issue on the import's report, so the caller gets the report and the file's\n * defect rather than a bare GraphFormatError.\n * @param err - what freezeWithReport() threw\n * @param report - the import's report\n * @returns the error to throw (anything that is not a GraphFormatError, unchanged)\n */\nfunction freezeFailure(err: unknown, report: ImportReport): unknown {\n if (!(err instanceof GraphFormatError) || err instanceof ImportError) {\n return err;\n }\n const issue = Object.freeze({\n category: \"validation-error\" as const,\n severity: \"error\" as const,\n code: err.code,\n message: err.message,\n line: null,\n element: null,\n });\n const failed: ImportReport = Object.freeze({\n ...report,\n issues: Object.freeze([...report.issues, issue]),\n errorCount: report.errorCount + 1,\n });\n return new ImportError(`the graph cannot be frozen: ${err.message}`, failed, { code: err.code, ...err.details });\n}\n\n/**\n * The E_UNSUPPORTED error of a format name nothing is registered under.\n * @param kind - importer or exporter\n * @param format - the requested name\n * @param known - the registered names\n * @returns the error\n */\nfunction unknownFormat(kind: \"importer\" | \"exporter\", format: string, known: Iterable<string>): GraphFormatError {\n const supported = [...known];\n return new GraphFormatError(\n \"E_UNSUPPORTED\",\n `no ${kind} is registered for format ${JSON.stringify(format)}; known: ${supported.join(\", \")}`,\n { option: \"format\", found: format, supported },\n );\n}\n\n/**\n * The hints of an import, for the unknown-format message.\n * @param options - the importGraph options\n * @returns \" (filename ..., MIME type ...)\" or an empty string\n */\nfunction describeHints(options: ImportGraphOptions): string {\n const parts: string[] = [];\n if (typeof options.filename === \"string\" && options.filename.length > 0) {\n parts.push(`filename ${JSON.stringify(options.filename)}`);\n }\n if (typeof options.mimeType === \"string\" && options.mimeType.length > 0) {\n parts.push(`MIME type ${JSON.stringify(options.mimeType)}`);\n }\n return parts.length === 0 ? \"\" : ` (${parts.join(\", \")})`;\n}\n\n/** A head read from an input, and the input to hand the importer (the same bytes, replayed for a stream). */\ninterface PeekedInput {\n /** The first bytes (or, for a text input, characters) of the content. */\n readonly head: Uint8Array | string;\n /** The input to read: the original for in-memory input, a replaying iterable for a stream. */\n readonly input: ImportInput;\n /**\n * Close the source when the importer never iterated the replaying input (it threw first, an\n * abort for instance): a stream's reader is canceled and released, an async generator finalised.\n * @returns when the source is closed\n */\n close(): Promise<void>;\n}\n\n/**\n * The first `bytes` of an input without consuming it: in-memory input is sliced; a stream or an\n * async iterable is read until enough is buffered and then replayed (the buffered chunks first,\n * the rest as it arrives) through a new async iterable that cancels the source when the importer\n * stops early.\n * @param input - the input\n * @param bytes - how much to peek\n * @param signal - the cancellation signal, or null\n * @returns the head and the input to read\n */\nasync function peekHead(input: ImportInput, bytes: number, signal: AbortSignal | null): Promise<PeekedInput> {\n if (typeof input === \"string\") {\n return { head: input.slice(0, bytes), input, close: (): Promise<void> => Promise.resolve() };\n }\n if (input instanceof Uint8Array) {\n return { head: input.subarray(0, bytes), input, close: (): Promise<void> => Promise.resolve() };\n }\n throwIfAborted(signal);\n const source: AsyncIterator<string | Uint8Array> =\n typeof (input as { getReader?: unknown }).getReader === \"function\"\n ? readerIterator(input as ReadableStream<Uint8Array>, signal)\n : (input as AsyncIterable<string | Uint8Array>)[Symbol.asyncIterator]();\n const buffered: (string | Uint8Array)[] = [];\n let size = 0;\n let finished = false;\n while (size < bytes) {\n if (signal?.aborted) {\n await source.return?.();\n throwIfAborted(signal);\n }\n const next = await source.next();\n if (next.done === true) {\n finished = true;\n break;\n }\n buffered.push(next.value);\n size += typeof next.value === \"string\" ? next.value.length : next.value.byteLength;\n }\n if (!finished && signal?.aborted) {\n // an abort that landed on the read completing the head: close the source before rethrowing\n await source.return?.();\n throwIfAborted(signal);\n }\n const replayed = replay(buffered, source, finished);\n return { head: joinHead(buffered, bytes), input: replayed, close: (): Promise<void> => replayed.close() };\n}\n\n/**\n * The head text or bytes of the buffered chunks: bytes when every chunk is bytes, text otherwise\n * (byte chunks decoded leniently; the importer decodes the real input strictly).\n * @param chunks - the buffered chunks\n * @param bytes - the head size\n * @returns the head\n */\nfunction joinHead(chunks: readonly (string | Uint8Array)[], bytes: number): Uint8Array | string {\n if (chunks.every((c) => c instanceof Uint8Array)) {\n const total = Math.min(\n bytes,\n chunks.reduce((sum, c) => sum + c.byteLength, 0),\n );\n const head = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n if (offset >= total) {\n break;\n }\n const part = chunk.subarray(0, Math.min(chunk.byteLength, total - offset));\n head.set(part, offset);\n offset += part.byteLength;\n }\n return head;\n }\n const decoder = new TextDecoder(\"utf-8\", { fatal: false });\n let text = \"\";\n for (const chunk of chunks) {\n text += typeof chunk === \"string\" ? chunk : decoder.decode(chunk, { stream: true });\n if (text.length >= bytes) {\n break;\n }\n }\n return text.slice(0, bytes);\n}\n\n/**\n * An async iterable that yields the buffered chunks, then the rest of the source; the source is\n * closed when the consumer stops early.\n * @param buffered - the chunks already read\n * @param source - the iterator positioned after them\n * @param finished - whether the source is already exhausted\n * @returns the replaying iterable\n */\nfunction replay(\n buffered: readonly (string | Uint8Array)[],\n source: AsyncIterator<string | Uint8Array>,\n finished: boolean,\n): AsyncIterable<string | Uint8Array> & { close(): Promise<void> } {\n let exhausted = finished;\n const close = async (): Promise<void> => {\n if (!exhausted) {\n exhausted = true;\n await source.return?.();\n }\n };\n return {\n close,\n [Symbol.asyncIterator](): AsyncIterator<string | Uint8Array> {\n let position = 0;\n return {\n async next(): Promise<IteratorResult<string | Uint8Array>> {\n if (position < buffered.length) {\n return { done: false, value: buffered[position++] };\n }\n if (exhausted) {\n return { done: true, value: undefined };\n }\n const next = await source.next();\n if (next.done === true) {\n exhausted = true;\n return { done: true, value: undefined };\n }\n return next;\n },\n async return(): Promise<IteratorResult<string | Uint8Array>> {\n await close();\n return { done: true, value: undefined };\n },\n };\n },\n };\n}\n\n/**\n * An async iterator over a ReadableStream's chunks that cancels the stream (with the signal's\n * reason) when closed early or when the signal fires during a read, and releases the reader when\n * the stream ends or errors.\n * @param stream - the stream\n * @param signal - the cancellation signal, or null\n * @returns the iterator\n */\nfunction readerIterator(stream: ReadableStream<Uint8Array>, signal: AbortSignal | null): AsyncIterator<Uint8Array> {\n const reader = lockReader(stream);\n let done = false;\n return {\n async next(): Promise<IteratorResult<Uint8Array>> {\n if (done) {\n return { done: true, value: undefined };\n }\n let result: ReadableStreamReadResult<Uint8Array>;\n try {\n result = await abortable(reader.read(), signal);\n } catch (err) {\n done = true;\n await reader.cancel(signal?.reason).catch(() => undefined);\n reader.releaseLock();\n throw err;\n }\n if (result.done) {\n done = true;\n reader.releaseLock();\n return { done: true, value: undefined };\n }\n return { done: false, value: result.value };\n },\n async return(): Promise<IteratorResult<Uint8Array>> {\n if (!done) {\n done = true;\n await reader.cancel(signal?.reason).catch(() => undefined);\n reader.releaseLock();\n }\n return { done: true, value: undefined };\n },\n };\n}\n\n// ============================================================ network sources (experimental)\n\n/**\n * Load a graph from a network source: a built-in one by id (\"ndex\", \"neo4j\", \"openalex\", ...),\n * one you registered with registerSource(), or a source object. The source fetches through a\n * guarded fetch that sends the credential only to the endpoint's origin, never over plain http\n * (except to this machine), never across a redirect, and retries what is safe to retry. Every\n * failure is an ImportError whose `issue.code` is one of SOURCE_ISSUE and whose `issue.params`\n * holds its values. A capped load warns W_SOURCE_LIMIT and gives `report.source.next`, which you\n * pass as `cursor` to continue. `result.format` is \"source:<id>\", or the format a file source\n * was read as. Experimental.\n * @param source - the source id\n * @param params - its params, typed by SourceParamsMap\n * @param options - endpoint, credential, cursor, caps, retries and the import options\n * @returns the graph, the format and the report\n * @example\n * ```ts\n * const { snapshot } = await loadFromSource(\"people\", { team: \"core\" }, { endpoint: \"https://example.com\" });\n * ```\n * @category Network sources\n */\nexport function loadFromSource<K extends keyof SourceParamsMap>(\n source: K,\n params: SourceParamsMap[K],\n options?: LoadFromSourceOptions,\n): Promise<ImportGraphResult>;\n/**\n * Load a graph from a network source by id or as an object. Experimental.\n * @param source - the source id or the source\n * @param params - its params\n * @param options - endpoint, credential, cursor, caps, retries and the import options\n * @returns the graph, the format and the report\n * @category Network sources\n */\nexport function loadFromSource<P>(\n source: string | GraphSource<P>,\n params: P,\n options?: LoadFromSourceOptions,\n): Promise<ImportGraphResult>;\n/**\n * The implementation of both loadFromSource() signatures.\n * @param source - the source id or the source\n * @param params - its params\n * @param options - the options\n * @returns the graph, the format and the report\n */\nexport function loadFromSource(\n source: string | GraphSource<never>,\n params: unknown,\n options?: LoadFromSourceOptions,\n): Promise<ImportGraphResult> {\n return registry.loadFromSource(source, params as Readonly<Record<string, unknown>>, options);\n}\n\n/**\n * Load from a network source into a sink you own (a GraphBuilder you keep filling). Experimental.\n * @param source - the source id or the source\n * @param params - its params\n * @param sink - where to write\n * @param options - the options of loadFromSource()\n * @returns the report\n * @category Network sources\n */\nexport function importFromSource<P>(\n source: string | GraphSource<P>,\n params: P,\n sink: GraphSink,\n options?: LoadFromSourceOptions,\n): Promise<ImportReport> {\n return registry.importFromSource(source, params as Readonly<Record<string, unknown>>, sink, options);\n}\n\n/**\n * Fetch the neighborhood of some nodes from a source that can expand: a graph of only what was\n * fetched (the seeds, their neighbors and the edges between them), to merge into the graph you\n * hold. A source without `expand` rejects with E_SOURCE_UNSUPPORTED. Experimental.\n * @param source - the source id or the source\n * @param request - the params, seeds, depth, direction and limit\n * @param options - the options of loadFromSource()\n * @returns the fetched part, the format and the report\n * @category Network sources\n */\nexport function expandFromSource<P>(\n source: string | GraphSource<P>,\n request: ExpandRequest<P>,\n options?: LoadFromSourceOptions,\n): Promise<ImportGraphResult> {\n return registry.expandFromSource(source, request as ExpandRequest<Readonly<Record<string, unknown>>>, options);\n}\n\n/**\n * Check a source's params and credential without loading the graph. Experimental.\n * @param source - the source id or the source\n * @param params - its params\n * @param options - the options of loadFromSource()\n * @returns what the service said\n * @category Network sources\n */\nexport function probeSource<P>(\n source: string | GraphSource<P>,\n params: P,\n options?: LoadFromSourceOptions,\n): Promise<SourceProbe> {\n return registry.probeSource(source, params as Readonly<Record<string, unknown>>, options);\n}\n\n/**\n * Search what a source holds (NDEx networks, ...). Experimental.\n * @param source - the source id or the source\n * @param query - params narrowing the search, the search text, cursor and page size\n * @param options - the options of loadFromSource()\n * @returns one page of results\n * @category Network sources\n */\nexport function listFromSource<P>(\n source: string | GraphSource<P>,\n query: SourceListQuery<P>,\n options?: LoadFromSourceOptions,\n): Promise<SourceListing> {\n return registry.listFromSource(source, query, options);\n}\n\n/**\n * Tell whether data loaded from a source earlier changed. Experimental.\n * @param source - the source id or the source\n * @param params - the params it was loaded with\n * @param seen - the validators recorded then (`report.source.validators`)\n * @param options - the options of loadFromSource()\n * @returns current, changed or unverifiable\n * @category Network sources\n */\nexport function validateSource<P>(\n source: string | GraphSource<P>,\n params: P,\n seen: SourceValidators,\n options?: LoadFromSourceOptions,\n): Promise<SourceFreshness> {\n return registry.validateSource(source, params as Readonly<Record<string, unknown>>, seen, options);\n}\n\n/**\n * Register a network source in the default registry, so loadFromSource() and graphty-element\n * find it by id. Throws an ImportError with E_SOURCE_INVALID for a malformed source or an id\n * already taken. Experimental.\n * @param source - the source, or a lazy source that loads its code on first use\n * @category Network sources\n */\nexport function registerSource<P>(source: GraphSource<P> | LazySource): void {\n registry.registerSource(source);\n}\n\n/**\n * Every source in the default registry with its descriptor (what a form asks for), loading no\n * source code. Experimental.\n * @returns one entry per source: id, descriptor, whether its code is loaded\n * @category Network sources\n */\nexport function listSources(): readonly SourceInfo[] {\n return registry.listSources();\n}\n","/**\n * Testing a source without a network: `replayFetch` answers requests from recorded responses and\n * refuses any request it has no recording for. Browser-safe (no file system), so a graphty-element\n * story and a third party's tests use it the same way.\n */\n\n/**\n * One recorded exchange. Experimental.\n * @category Network sources\n */\nexport interface Recording {\n /** The request method. @defaultValue \"GET\" */\n readonly method?: string | undefined;\n /** The request URL. Query parameters match in any order. */\n readonly url: string;\n /** The request body, when it must match (JSON bodies compare as JSON). */\n readonly requestBody?: string | undefined;\n /**\n * true: the request must carry a credential; false: it must not. Absent: either. A credential\n * is an Authorization header, or a header or query parameter named in `secretHeaders` /\n * `secretQuery`; its value is never compared.\n */\n readonly credential?: boolean | undefined;\n /** The response status. @defaultValue 200 */\n readonly status?: number | undefined;\n /** The response headers. */\n readonly headers?: Readonly<Record<string, string>> | undefined;\n /** The response body: text, or a value sent as JSON. */\n readonly body?: unknown;\n}\n\n/**\n * The options of `replayFetch`. Experimental.\n * @category Network sources\n */\nexport interface ReplayOptions {\n /** What an unrecorded request does: \"throw\" (the only choice; the test fails). @defaultValue \"throw\" */\n readonly onUnrecorded?: \"throw\" | undefined;\n /** Query parameters that hold a credential: ignored when matching, counted as a credential. */\n readonly secretQuery?: readonly string[] | undefined;\n /** Request headers that hold a credential, beside Authorization. */\n readonly secretHeaders?: readonly string[] | undefined;\n}\n\n/**\n * One request `replayFetch` answered. Experimental.\n * @category Network sources\n */\nexport interface ReplayCall {\n /** The method. */\n readonly method: string;\n /** The URL, origin and path only. */\n readonly url: string;\n /** Whether a credential was sent. */\n readonly credential: boolean;\n}\n\n/**\n * A fetch that answers from recordings, plus the requests it answered. Experimental.\n * @category Network sources\n */\nexport type ReplayFetch = typeof fetch & {\n /** The requests answered, in order. */\n readonly calls: readonly ReplayCall[];\n};\n\n/**\n * A fetch that answers every request from recordings: the first unused recording that matches\n * (method, URL with its query in any order, body when recorded, and whether a credential was\n * sent), else the last one that matched, so a recording answers every repeat. A request with no\n * matching recording rejects with an Error naming its method and URL, which a source never\n * retries. Like fetch, a request whose signal is already aborted rejects with the signal's\n * reason. Pass it as the `fetch` option. Experimental.\n * @param recordings - the recorded exchanges\n * @param options - which headers and query parameters hold a credential\n * @returns the fetch\n * @example\n * ```ts\n * const fetch = replayFetch([{ url: \"https://example.com/api/people.json?team=core\", body: [{ id: \"ana\", knows: [] }] }]);\n * await loadFromSource(\"people\", { team: \"core\" }, { endpoint: \"https://example.com\", fetch });\n * ```\n * @category Network sources\n */\nexport function replayFetch(recordings: readonly Recording[], options: ReplayOptions = {}): ReplayFetch {\n const secretQuery = new Set(options.secretQuery ?? []);\n const secretHeaders = [\"authorization\", ...(options.secretHeaders ?? []).map((h) => h.toLowerCase())];\n const used = new Set<number>();\n const calls: ReplayCall[] = [];\n\n const key = (url: URL): string => {\n const params = [...url.searchParams].filter(([k]) => !secretQuery.has(k)).sort(compare);\n return `${url.origin}${url.pathname}?${new URLSearchParams(params).toString()}`;\n };\n\n const replay = async (input: string | URL | Request, init?: RequestInit): Promise<Response> => {\n const request = new Request(input, init);\n // like fetch: an aborted signal rejects with its reason before anything is answered\n request.signal.throwIfAborted();\n const url = new URL(request.url);\n const method = request.method.toUpperCase();\n const body = method === \"GET\" || method === \"HEAD\" ? \"\" : await request.clone().text();\n const credential =\n secretHeaders.some((h) => request.headers.has(h)) ||\n [...url.searchParams.keys()].some((k) => secretQuery.has(k));\n const wanted = key(url);\n const matches: number[] = [];\n recordings.forEach((r, i) => {\n if (\n (r.method ?? \"GET\").toUpperCase() === method &&\n key(new URL(r.url)) === wanted &&\n (r.credential === undefined || r.credential === credential) &&\n (r.requestBody === undefined || sameBody(r.requestBody, body))\n ) {\n matches.push(i);\n }\n });\n const index = matches.find((i) => !used.has(i)) ?? matches.at(-1);\n if (index === undefined) {\n throw new Error(`replayFetch: no recording for ${method} ${url.origin}${url.pathname}`);\n }\n used.add(index);\n calls.push({ method, url: `${url.origin}${url.pathname}`, credential });\n const r = recordings[index];\n const status = r.status ?? 200;\n const text = bodyText(r.body);\n const headers = new Headers(r.headers);\n if (text !== null && typeof r.body !== \"string\" && !headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n const nullBody = status === 204 || status === 304 || (status >= 300 && status < 400 && text === null);\n return new Response(nullBody ? null : text, { status, headers });\n };\n return Object.assign(replay, { calls });\n}\n\n/**\n * A recorded body as response text.\n * @param body - the recorded body\n * @returns the text, or null for no body\n */\nfunction bodyText(body: unknown): string | null {\n if (body === undefined || body === null) {\n return null;\n }\n return typeof body === \"string\" ? body : JSON.stringify(body);\n}\n\n/**\n * Compare two query entries by key, then value.\n * @param a - one entry\n * @param b - another\n * @returns the order\n */\nfunction compare(a: [string, string], b: [string, string]): number {\n return a[0] === b[0] ? a[1].localeCompare(b[1]) : a[0].localeCompare(b[0]);\n}\n\n/**\n * Whether two bodies are the same, as JSON when both parse.\n * @param recorded - the recorded body\n * @param sent - the sent body\n * @returns true when they match\n */\nfunction sameBody(recorded: string, sent: string): boolean {\n try {\n return JSON.stringify(JSON.parse(recorded)) === JSON.stringify(JSON.parse(sent));\n } catch {\n return recorded === sent;\n }\n}\n\n/**\n * A recording made from a real exchange, without its credential: the request's headers are never\n * kept, query parameters named in `secretQuery` are removed from the URL, and of the response only\n * the status, the Content-Type and the headers named in `keepHeaders` are kept. Experimental.\n * @param request - the request sent\n * @param response - its response (read; pass a clone to keep using it)\n * @param options - what to keep and drop\n * @param options.keepHeaders - response headers to keep beside Content-Type\n * @param options.secretQuery - query parameters removed from the URL\n * @returns the recording\n * @category Network sources\n */\nexport async function recordingFrom(\n request: Request,\n response: Response,\n options: { readonly keepHeaders?: readonly string[]; readonly secretQuery?: readonly string[] } = {},\n): Promise<Recording> {\n const headers: Record<string, string> = {};\n for (const name of [\"content-type\", ...(options.keepHeaders ?? [])]) {\n const value = response.headers.get(name);\n if (value !== null) {\n headers[name.toLowerCase()] = value;\n }\n }\n const url = new URL(request.url);\n for (const name of options.secretQuery ?? []) {\n url.searchParams.delete(name);\n }\n const method = request.method.toUpperCase();\n const requestBody = method === \"GET\" || method === \"HEAD\" ? undefined : await request.clone().text();\n return {\n method,\n url: url.toString(),\n ...(requestBody === undefined || requestBody === \"\" ? {} : { requestBody }),\n status: response.status,\n headers,\n body: await response.text(),\n };\n}\n"],"names":["sniff","attributes","s","t","e","a","n","i","al","aw","av","r","v","k","b","d","p","result","w","importerOptions","f","c","h","replay"],"mappings":"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"}
|