@graphty/graph-io 0.3.46 → 0.3.48
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-wWjCRzKj.js → approximations-C2riR4NT.js} +2 -2
- package/dist/chunks/{approximations-wWjCRzKj.js.map → approximations-C2riR4NT.js.map} +1 -1
- package/dist/chunks/{block-DiGq58c3.js → block-Cu22ewuS.js} +92 -21
- package/dist/chunks/block-Cu22ewuS.js.map +1 -0
- package/dist/chunks/{choose--jM0yYCo.js → choose-Cdx6Enl2.js} +3 -3
- package/dist/chunks/{choose--jM0yYCo.js.map → choose-Cdx6Enl2.js.map} +1 -1
- package/dist/chunks/codes-CV_Bhcyi.js +153 -0
- package/dist/chunks/codes-CV_Bhcyi.js.map +1 -0
- package/dist/chunks/{constants-BKwqelYD.js → constants-D0LqcsLJ.js} +2 -2
- package/dist/chunks/{constants-BKwqelYD.js.map → constants-D0LqcsLJ.js.map} +1 -1
- package/dist/chunks/context-cgmmOxZ2.js +663 -0
- package/dist/chunks/context-cgmmOxZ2.js.map +1 -0
- package/dist/chunks/credentials-BiQsnMTb.js +347 -0
- package/dist/chunks/credentials-BiQsnMTb.js.map +1 -0
- package/dist/chunks/cx-export-BEeF6ymo.js +259 -0
- package/dist/chunks/cx-export-BEeF6ymo.js.map +1 -0
- package/dist/chunks/descriptor-BJ-W0Jd-.js +137 -0
- package/dist/chunks/descriptor-BJ-W0Jd-.js.map +1 -0
- package/dist/chunks/descriptor-C-YDhtsn.js +48 -0
- package/dist/chunks/descriptor-C-YDhtsn.js.map +1 -0
- package/dist/chunks/{emit-CwU8cUmG.js → emit-CD8xnY8s.js} +70 -10
- package/dist/chunks/emit-CD8xnY8s.js.map +1 -0
- package/dist/chunks/{escape-CgzxiYPg.js → escape-DH2Egt-l.js} +12 -12
- package/dist/chunks/{escape-CgzxiYPg.js.map → escape-DH2Egt-l.js.map} +1 -1
- package/dist/chunks/{export-BvqAXCKh.js → export-CZ7VRm4I.js} +53 -1443
- package/dist/chunks/export-CZ7VRm4I.js.map +1 -0
- package/dist/chunks/{exporter-DndFlGSa.js → exporter-BIdaoIgh.js} +7 -6
- package/dist/chunks/{exporter-DndFlGSa.js.map → exporter-BIdaoIgh.js.map} +1 -1
- package/dist/chunks/{exporter-CJgfhF-l.js → exporter-ChjL5fmP.js} +8 -7
- package/dist/chunks/{exporter-CJgfhF-l.js.map → exporter-ChjL5fmP.js.map} +1 -1
- package/dist/chunks/{exporter--Mk9gXCJ.js → exporter-Dcw7Ldtq.js} +6 -4
- package/dist/chunks/{exporter--Mk9gXCJ.js.map → exporter-Dcw7Ldtq.js.map} +1 -1
- package/dist/chunks/exporter-DtVU80Fa.js +1008 -0
- package/dist/chunks/exporter-DtVU80Fa.js.map +1 -0
- package/dist/chunks/{exporter-CrDWIyiq.js → exporter-bxxjOrDZ.js} +11 -9
- package/dist/chunks/{exporter-CrDWIyiq.js.map → exporter-bxxjOrDZ.js.map} +1 -1
- package/dist/chunks/format-BMS-1Nxb.js +64 -0
- package/dist/chunks/format-BMS-1Nxb.js.map +1 -0
- package/dist/chunks/{generic-Dq1ntt9q.js → generic-CP6YD34u.js} +4 -4
- package/dist/chunks/{generic-Dq1ntt9q.js.map → generic-CP6YD34u.js.map} +1 -1
- package/dist/chunks/{importer-DiZRmOQG.js → importer-B87_fmVx.js} +13 -17
- package/dist/chunks/importer-B87_fmVx.js.map +1 -0
- package/dist/chunks/{importer-BSvfrX_h.js → importer-Bji2MeWr.js} +18 -1014
- package/dist/chunks/importer-Bji2MeWr.js.map +1 -0
- package/dist/chunks/{importer-COTK9Tsl.js → importer-CB_zV5_L.js} +14 -11
- package/dist/chunks/importer-CB_zV5_L.js.map +1 -0
- package/dist/chunks/{importer-e6LGpqHB.js → importer-CVT-JyDE.js} +12 -9
- package/dist/chunks/importer-CVT-JyDE.js.map +1 -0
- package/dist/chunks/{importer-yh_aBCU6.js → importer-Cyy6UseH.js} +7 -6
- package/dist/chunks/{importer-yh_aBCU6.js.map → importer-Cyy6UseH.js.map} +1 -1
- package/dist/chunks/{importer-iFYPEKaJ.js → importer-DPZDN40-.js} +14 -10
- package/dist/chunks/{importer-iFYPEKaJ.js.map → importer-DPZDN40-.js.map} +1 -1
- package/dist/chunks/{importer-CMmeMWlC.js → importer-e3huMZbm.js} +8 -260
- package/dist/chunks/importer-e3huMZbm.js.map +1 -0
- package/dist/chunks/input-Ccg9I22A.js +1397 -0
- package/dist/chunks/input-Ccg9I22A.js.map +1 -0
- package/dist/chunks/{json-elements-DJZRZ6jd.js → json-elements-By172SVq.js} +4 -4
- package/dist/chunks/{json-elements-DJZRZ6jd.js.map → json-elements-By172SVq.js.map} +1 -1
- package/dist/chunks/{lexicon-CT69Kd87.js → lexicon-u2SI5xcx.js} +19 -5
- package/dist/chunks/lexicon-u2SI5xcx.js.map +1 -0
- package/dist/chunks/{ontology-export-G4MqRdux.js → ontology-export-BwgMyuF0.js} +4 -3
- package/dist/chunks/{ontology-export-G4MqRdux.js.map → ontology-export-BwgMyuF0.js.map} +1 -1
- package/dist/chunks/{records-CiaWZrFH.js → records-Cgvxz-Vx.js} +2 -2
- package/dist/chunks/{records-CiaWZrFH.js.map → records-Cgvxz-Vx.js.map} +1 -1
- package/dist/chunks/{format-BpQBx8MZ.js → report-CgdsL9Hb.js} +72 -129
- package/dist/chunks/report-CgdsL9Hb.js.map +1 -0
- package/dist/chunks/sigv4-LkAzsLAu.js +247 -0
- package/dist/chunks/sigv4-LkAzsLAu.js.map +1 -0
- package/dist/chunks/{styles-BQnsga7p.js → styles-CaABMoO1.js} +76 -43
- package/dist/chunks/styles-CaABMoO1.js.map +1 -0
- package/dist/chunks/{styles-D3fRphrO.js → styles-P_gmFAOi.js} +101 -21
- package/dist/chunks/styles-P_gmFAOi.js.map +1 -0
- package/dist/chunks/{styles-yed-BF5x3_Y5.js → styles-yed-Cs1nmrjn.js} +60 -20
- package/dist/chunks/styles-yed-Cs1nmrjn.js.map +1 -0
- package/dist/chunks/{text-CzJNFOS9.js → text-BuKQVMz2.js} +2 -2
- package/dist/chunks/{text-CzJNFOS9.js.map → text-BuKQVMz2.js.map} +1 -1
- package/dist/chunks/{writer-DMKvthQE.js → writer-DvHTl36J.js} +5 -4
- package/dist/chunks/writer-DvHTl36J.js.map +1 -0
- package/dist/csv.js +7 -5
- package/dist/csv.js.map +1 -1
- package/dist/cx.js +5 -4
- package/dist/cx.js.map +1 -1
- package/dist/cx2.js +2 -2
- package/dist/cys.js +1 -1
- package/dist/dot.js +2 -2
- package/dist/gexf.js +7 -5
- package/dist/gexf.js.map +1 -1
- package/dist/gml.js +16 -13
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +1181 -224
- package/dist/graph-io.js.map +1 -1
- package/dist/graphml.js +3 -3
- package/dist/json.js +1 -1
- package/dist/neo4j.js +6 -4
- package/dist/neo4j.js.map +1 -1
- package/dist/obo.js +1 -1
- package/dist/pajek.js +1 -1
- package/dist/sources-cypher.d.ts +1 -0
- package/dist/sources-cypher.js +1236 -0
- package/dist/sources-cypher.js.map +1 -0
- package/dist/sources-ndex.d.ts +1 -0
- package/dist/sources-ndex.js +278 -0
- package/dist/sources-ndex.js.map +1 -0
- package/dist/sources-rest.d.ts +1 -0
- package/dist/sources-rest.js +1367 -0
- package/dist/sources-rest.js.map +1 -0
- package/dist/src/common/report.d.ts +6 -3
- package/dist/src/common/report.d.ts.map +1 -1
- package/dist/src/common/report.js +15 -9
- package/dist/src/common/report.js.map +1 -1
- package/dist/src/formats/cx/styles.d.ts.map +1 -1
- package/dist/src/formats/cx/styles.js +1 -0
- package/dist/src/formats/cx/styles.js.map +1 -1
- package/dist/src/formats/dot/styles.d.ts.map +1 -1
- package/dist/src/formats/dot/styles.js +3 -1
- package/dist/src/formats/dot/styles.js.map +1 -1
- package/dist/src/formats/gexf/styles.d.ts +29 -12
- package/dist/src/formats/gexf/styles.d.ts.map +1 -1
- package/dist/src/formats/gexf/styles.js +160 -31
- package/dist/src/formats/gexf/styles.js.map +1 -1
- package/dist/src/formats/gml/styles.d.ts.map +1 -1
- package/dist/src/formats/gml/styles.js +5 -4
- 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 +3 -3
- package/dist/src/formats/graphml/styles-plain.js.map +1 -1
- package/dist/src/formats/graphml/styles-yed.d.ts.map +1 -1
- package/dist/src/formats/graphml/styles-yed.js +89 -19
- package/dist/src/formats/graphml/styles-yed.js.map +1 -1
- package/dist/src/formats/pajek/styles.d.ts.map +1 -1
- package/dist/src/formats/pajek/styles.js +1 -0
- package/dist/src/formats/pajek/styles.js.map +1 -1
- package/dist/src/formats/xgmml/styles.d.ts.map +1 -1
- package/dist/src/formats/xgmml/styles.js +1 -0
- package/dist/src/formats/xgmml/styles.js.map +1 -1
- package/dist/src/index.d.ts +8 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +9 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/registry.d.ts +173 -1
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +196 -1
- package/dist/src/registry.js.map +1 -1
- package/dist/src/sources/builtins.d.ts +11 -0
- package/dist/src/sources/builtins.d.ts.map +1 -0
- package/dist/src/sources/builtins.js +47 -0
- package/dist/src/sources/builtins.js.map +1 -0
- package/dist/src/sources/codes.d.ts +230 -0
- package/dist/src/sources/codes.d.ts.map +1 -0
- package/dist/src/sources/codes.js +58 -0
- package/dist/src/sources/codes.js.map +1 -0
- package/dist/src/sources/context.d.ts +112 -0
- package/dist/src/sources/context.d.ts.map +1 -0
- package/dist/src/sources/context.js +739 -0
- package/dist/src/sources/context.js.map +1 -0
- package/dist/src/sources/credentials.d.ts +179 -0
- package/dist/src/sources/credentials.d.ts.map +1 -0
- package/dist/src/sources/credentials.js +301 -0
- package/dist/src/sources/credentials.js.map +1 -0
- package/dist/src/sources/cypher/descriptor.d.ts +21 -0
- package/dist/src/sources/cypher/descriptor.d.ts.map +1 -0
- package/dist/src/sources/cypher/descriptor.js +119 -0
- package/dist/src/sources/cypher/descriptor.js.map +1 -0
- package/dist/src/sources/cypher/flatten.d.ts +72 -0
- package/dist/src/sources/cypher/flatten.d.ts.map +1 -0
- package/dist/src/sources/cypher/flatten.js +279 -0
- package/dist/src/sources/cypher/flatten.js.map +1 -0
- package/dist/src/sources/cypher/index.d.ts +33 -0
- package/dist/src/sources/cypher/index.d.ts.map +1 -0
- package/dist/src/sources/cypher/index.js +405 -0
- package/dist/src/sources/cypher/index.js.map +1 -0
- package/dist/src/sources/cypher/params.d.ts +40 -0
- package/dist/src/sources/cypher/params.d.ts.map +1 -0
- package/dist/src/sources/cypher/params.js +6 -0
- package/dist/src/sources/cypher/params.js.map +1 -0
- package/dist/src/sources/cypher/profiles.d.ts +44 -0
- package/dist/src/sources/cypher/profiles.d.ts.map +1 -0
- package/dist/src/sources/cypher/profiles.js +61 -0
- package/dist/src/sources/cypher/profiles.js.map +1 -0
- package/dist/src/sources/cypher/query-builder.d.ts +106 -0
- package/dist/src/sources/cypher/query-builder.d.ts.map +1 -0
- package/dist/src/sources/cypher/query-builder.js +236 -0
- package/dist/src/sources/cypher/query-builder.js.map +1 -0
- package/dist/src/sources/cypher/transports/bolt.d.ts +21 -0
- package/dist/src/sources/cypher/transports/bolt.d.ts.map +1 -0
- package/dist/src/sources/cypher/transports/bolt.js +185 -0
- package/dist/src/sources/cypher/transports/bolt.js.map +1 -0
- package/dist/src/sources/cypher/transports/neptune-analytics.d.ts +15 -0
- package/dist/src/sources/cypher/transports/neptune-analytics.d.ts.map +1 -0
- package/dist/src/sources/cypher/transports/neptune-analytics.js +38 -0
- package/dist/src/sources/cypher/transports/neptune-analytics.js.map +1 -0
- package/dist/src/sources/cypher/transports/neptune-https.d.ts +31 -0
- package/dist/src/sources/cypher/transports/neptune-https.d.ts.map +1 -0
- package/dist/src/sources/cypher/transports/neptune-https.js +104 -0
- package/dist/src/sources/cypher/transports/neptune-https.js.map +1 -0
- package/dist/src/sources/cypher/transports/query-api.d.ts +14 -0
- package/dist/src/sources/cypher/transports/query-api.d.ts.map +1 -0
- package/dist/src/sources/cypher/transports/query-api.js +80 -0
- package/dist/src/sources/cypher/transports/query-api.js.map +1 -0
- package/dist/src/sources/cypher/transports/transport.d.ts +78 -0
- package/dist/src/sources/cypher/transports/transport.d.ts.map +1 -0
- package/dist/src/sources/cypher/transports/transport.js +77 -0
- package/dist/src/sources/cypher/transports/transport.js.map +1 -0
- package/dist/src/sources/cypher/types-map.d.ts +91 -0
- package/dist/src/sources/cypher/types-map.d.ts.map +1 -0
- package/dist/src/sources/cypher/types-map.js +306 -0
- package/dist/src/sources/cypher/types-map.js.map +1 -0
- package/dist/src/sources/define.d.ts +47 -0
- package/dist/src/sources/define.d.ts.map +1 -0
- package/dist/src/sources/define.js +173 -0
- package/dist/src/sources/define.js.map +1 -0
- package/dist/src/sources/fail.d.ts +33 -0
- package/dist/src/sources/fail.d.ts.map +1 -0
- package/dist/src/sources/fail.js +49 -0
- package/dist/src/sources/fail.js.map +1 -0
- package/dist/src/sources/ids.d.ts +64 -0
- package/dist/src/sources/ids.d.ts.map +1 -0
- package/dist/src/sources/ids.js +64 -0
- package/dist/src/sources/ids.js.map +1 -0
- package/dist/src/sources/ndex/client.d.ts +31 -0
- package/dist/src/sources/ndex/client.d.ts.map +1 -0
- package/dist/src/sources/ndex/client.js +90 -0
- package/dist/src/sources/ndex/client.js.map +1 -0
- package/dist/src/sources/ndex/descriptor.d.ts +10 -0
- package/dist/src/sources/ndex/descriptor.d.ts.map +1 -0
- package/dist/src/sources/ndex/descriptor.js +55 -0
- package/dist/src/sources/ndex/descriptor.js.map +1 -0
- package/dist/src/sources/ndex/expand.d.ts +20 -0
- package/dist/src/sources/ndex/expand.d.ts.map +1 -0
- package/dist/src/sources/ndex/expand.js +87 -0
- package/dist/src/sources/ndex/expand.js.map +1 -0
- package/dist/src/sources/ndex/index.d.ts +25 -0
- package/dist/src/sources/ndex/index.d.ts.map +1 -0
- package/dist/src/sources/ndex/index.js +191 -0
- package/dist/src/sources/ndex/index.js.map +1 -0
- package/dist/src/sources/ndex/params.d.ts +17 -0
- package/dist/src/sources/ndex/params.d.ts.map +1 -0
- package/dist/src/sources/ndex/params.js +6 -0
- package/dist/src/sources/ndex/params.js.map +1 -0
- package/dist/src/sources/ndex/share-url.d.ts +40 -0
- package/dist/src/sources/ndex/share-url.d.ts.map +1 -0
- package/dist/src/sources/ndex/share-url.js +64 -0
- package/dist/src/sources/ndex/share-url.js.map +1 -0
- package/dist/src/sources/params.d.ts +28 -0
- package/dist/src/sources/params.d.ts.map +1 -0
- package/dist/src/sources/params.js +6 -0
- package/dist/src/sources/params.js.map +1 -0
- package/dist/src/sources/registry.d.ts +118 -0
- package/dist/src/sources/registry.d.ts.map +1 -0
- package/dist/src/sources/registry.js +193 -0
- package/dist/src/sources/registry.js.map +1 -0
- package/dist/src/sources/rest/descriptor.d.ts +16 -0
- package/dist/src/sources/rest/descriptor.d.ts.map +1 -0
- package/dist/src/sources/rest/descriptor.js +71 -0
- package/dist/src/sources/rest/descriptor.js.map +1 -0
- package/dist/src/sources/rest/index.d.ts +14 -0
- package/dist/src/sources/rest/index.d.ts.map +1 -0
- package/dist/src/sources/rest/index.js +13 -0
- package/dist/src/sources/rest/index.js.map +1 -0
- package/dist/src/sources/rest/mapping.d.ts +30 -0
- package/dist/src/sources/rest/mapping.d.ts.map +1 -0
- package/dist/src/sources/rest/mapping.js +362 -0
- package/dist/src/sources/rest/mapping.js.map +1 -0
- package/dist/src/sources/rest/openalex.d.ts +27 -0
- package/dist/src/sources/rest/openalex.d.ts.map +1 -0
- package/dist/src/sources/rest/openalex.js +269 -0
- package/dist/src/sources/rest/openalex.js.map +1 -0
- package/dist/src/sources/rest/paging.d.ts +53 -0
- package/dist/src/sources/rest/paging.d.ts.map +1 -0
- package/dist/src/sources/rest/paging.js +138 -0
- package/dist/src/sources/rest/paging.js.map +1 -0
- package/dist/src/sources/rest/params.d.ts +216 -0
- package/dist/src/sources/rest/params.d.ts.map +1 -0
- package/dist/src/sources/rest/params.js +7 -0
- package/dist/src/sources/rest/params.js.map +1 -0
- package/dist/src/sources/rest/records.d.ts +41 -0
- package/dist/src/sources/rest/records.d.ts.map +1 -0
- package/dist/src/sources/rest/records.js +240 -0
- package/dist/src/sources/rest/records.js.map +1 -0
- package/dist/src/sources/rest/samples/deps-dev.d.ts +10 -0
- package/dist/src/sources/rest/samples/deps-dev.d.ts.map +1 -0
- package/dist/src/sources/rest/samples/deps-dev.js +47 -0
- package/dist/src/sources/rest/samples/deps-dev.js.map +1 -0
- package/dist/src/sources/rest/samples/string.d.ts +9 -0
- package/dist/src/sources/rest/samples/string.d.ts.map +1 -0
- package/dist/src/sources/rest/samples/string.js +42 -0
- package/dist/src/sources/rest/samples/string.js.map +1 -0
- package/dist/src/sources/rest/selectors.d.ts +41 -0
- package/dist/src/sources/rest/selectors.d.ts.map +1 -0
- package/dist/src/sources/rest/selectors.js +81 -0
- package/dist/src/sources/rest/selectors.js.map +1 -0
- package/dist/src/sources/rest/source.d.ts +67 -0
- package/dist/src/sources/rest/source.d.ts.map +1 -0
- package/dist/src/sources/rest/source.js +635 -0
- package/dist/src/sources/rest/source.js.map +1 -0
- package/dist/src/sources/rest/templates.d.ts +38 -0
- package/dist/src/sources/rest/templates.d.ts.map +1 -0
- package/dist/src/sources/rest/templates.js +125 -0
- package/dist/src/sources/rest/templates.js.map +1 -0
- package/dist/src/sources/run.d.ts +93 -0
- package/dist/src/sources/run.d.ts.map +1 -0
- package/dist/src/sources/run.js +673 -0
- package/dist/src/sources/run.js.map +1 -0
- package/dist/src/sources/sha256.d.ts +12 -0
- package/dist/src/sources/sha256.d.ts.map +1 -0
- package/dist/src/sources/sha256.js +95 -0
- package/dist/src/sources/sha256.js.map +1 -0
- package/dist/src/sources/sigv4.d.ts +24 -0
- package/dist/src/sources/sigv4.d.ts.map +1 -0
- package/dist/src/sources/sigv4.js +182 -0
- package/dist/src/sources/sigv4.js.map +1 -0
- package/dist/src/sources/testing.d.ts +96 -0
- package/dist/src/sources/testing.d.ts.map +1 -0
- package/dist/src/sources/testing.js +138 -0
- package/dist/src/sources/testing.js.map +1 -0
- package/dist/src/sources/types.d.ts +665 -0
- package/dist/src/sources/types.d.ts.map +1 -0
- package/dist/src/sources/types.js +10 -0
- package/dist/src/sources/types.js.map +1 -0
- package/dist/src/styles/canon/enums.d.ts.map +1 -1
- package/dist/src/styles/canon/enums.js +1 -0
- package/dist/src/styles/canon/enums.js.map +1 -1
- package/dist/src/styles/cyjs/cascade.d.ts.map +1 -1
- package/dist/src/styles/cyjs/cascade.js +68 -2
- 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 +2 -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 +18 -7
- package/dist/src/styles/cyjs/emit.js.map +1 -1
- package/dist/src/styles/cyjs/mappers.d.ts +4 -1
- package/dist/src/styles/cyjs/mappers.d.ts.map +1 -1
- package/dist/src/styles/cyjs/mappers.js +2 -0
- package/dist/src/styles/cyjs/mappers.js.map +1 -1
- package/dist/src/styles/cytoscape/emit.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/emit.js +59 -7
- package/dist/src/styles/cytoscape/emit.js.map +1 -1
- package/dist/src/styles/cytoscape/lexicon.d.ts +6 -0
- package/dist/src/styles/cytoscape/lexicon.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/lexicon.js +26 -2
- package/dist/src/styles/cytoscape/lexicon.js.map +1 -1
- package/dist/src/styles/cytoscape/resolve.d.ts +4 -1
- package/dist/src/styles/cytoscape/resolve.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/resolve.js +10 -6
- package/dist/src/styles/cytoscape/resolve.js.map +1 -1
- package/dist/src/styles/cytoscape/translate.d.ts.map +1 -1
- package/dist/src/styles/cytoscape/translate.js +10 -10
- package/dist/src/styles/cytoscape/translate.js.map +1 -1
- package/dist/src/styles/defaults.d.ts +30 -0
- package/dist/src/styles/defaults.d.ts.map +1 -1
- package/dist/src/styles/defaults.js +45 -4
- package/dist/src/styles/defaults.js.map +1 -1
- package/dist/src/styles/io/block.d.ts.map +1 -1
- package/dist/src/styles/io/block.js +9 -0
- package/dist/src/styles/io/block.js.map +1 -1
- package/dist/src/styles/io/writer.d.ts.map +1 -1
- package/dist/src/styles/io/writer.js +7 -3
- package/dist/src/styles/io/writer.js.map +1 -1
- package/dist/src/styles/plan/resolve.d.ts +2 -1
- package/dist/src/styles/plan/resolve.d.ts.map +1 -1
- package/dist/src/styles/plan/resolve.js +13 -2
- package/dist/src/styles/plan/resolve.js.map +1 -1
- package/dist/src/styles/types.d.ts +19 -2
- package/dist/src/styles/types.d.ts.map +1 -1
- package/dist/src/styles/vocabulary.d.ts.map +1 -1
- package/dist/src/styles/vocabulary.js +15 -1
- package/dist/src/styles/vocabulary.js.map +1 -1
- package/dist/src/types.d.ts +19 -5
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/styles.js +11 -11
- package/dist/xgmml.js +3 -3
- package/docs/samples/people.json +6 -0
- package/package.json +29 -4
- package/src/common/report.ts +27 -7
- package/src/formats/cx/styles.ts +1 -0
- package/src/formats/dot/styles.ts +3 -1
- package/src/formats/gexf/styles.ts +185 -37
- package/src/formats/gml/styles.ts +5 -4
- package/src/formats/graphml/styles-plain.ts +3 -9
- package/src/formats/graphml/styles-yed.ts +93 -20
- package/src/formats/pajek/styles.ts +1 -0
- package/src/formats/xgmml/styles.ts +1 -0
- package/src/index.ts +90 -0
- package/src/registry.ts +326 -1
- package/src/sources/builtins.ts +56 -0
- package/src/sources/codes.ts +235 -0
- package/src/sources/context.ts +893 -0
- package/src/sources/credentials.ts +409 -0
- package/src/sources/cypher/descriptor.ts +125 -0
- package/src/sources/cypher/flatten.ts +323 -0
- package/src/sources/cypher/index.ts +498 -0
- package/src/sources/cypher/params.ts +41 -0
- package/src/sources/cypher/profiles.ts +78 -0
- package/src/sources/cypher/query-builder.ts +294 -0
- package/src/sources/cypher/transports/bolt.ts +228 -0
- package/src/sources/cypher/transports/neptune-analytics.ts +41 -0
- package/src/sources/cypher/transports/neptune-https.ts +122 -0
- package/src/sources/cypher/transports/query-api.ts +100 -0
- package/src/sources/cypher/transports/transport.ts +139 -0
- package/src/sources/cypher/types-map.ts +418 -0
- package/src/sources/define.ts +195 -0
- package/src/sources/fail.ts +70 -0
- package/src/sources/ids.ts +74 -0
- package/src/sources/ndex/client.ts +102 -0
- package/src/sources/ndex/descriptor.ts +64 -0
- package/src/sources/ndex/expand.ts +100 -0
- package/src/sources/ndex/index.ts +235 -0
- package/src/sources/ndex/params.ts +17 -0
- package/src/sources/ndex/share-url.ts +84 -0
- package/src/sources/params.ts +29 -0
- package/src/sources/registry.ts +325 -0
- package/src/sources/rest/descriptor.ts +74 -0
- package/src/sources/rest/index.ts +22 -0
- package/src/sources/rest/mapping.ts +401 -0
- package/src/sources/rest/openalex.ts +288 -0
- package/src/sources/rest/paging.ts +180 -0
- package/src/sources/rest/params.ts +243 -0
- package/src/sources/rest/records.ts +289 -0
- package/src/sources/rest/samples/deps-dev.ts +49 -0
- package/src/sources/rest/samples/string.ts +44 -0
- package/src/sources/rest/selectors.ts +91 -0
- package/src/sources/rest/source.ts +760 -0
- package/src/sources/rest/templates.ts +151 -0
- package/src/sources/run.ts +793 -0
- package/src/sources/sha256.ts +99 -0
- package/src/sources/sigv4.ts +207 -0
- package/src/sources/testing.ts +210 -0
- package/src/sources/types.ts +741 -0
- package/src/styles/canon/enums.ts +1 -0
- package/src/styles/cyjs/cascade.ts +81 -2
- package/src/styles/cyjs/defaults-table.ts +2 -0
- package/src/styles/cyjs/emit.ts +18 -7
- package/src/styles/cyjs/mappers.ts +6 -1
- package/src/styles/cytoscape/emit.ts +61 -7
- package/src/styles/cytoscape/lexicon.ts +28 -2
- package/src/styles/cytoscape/resolve.ts +22 -6
- package/src/styles/cytoscape/translate.ts +11 -11
- package/src/styles/defaults.ts +93 -4
- package/src/styles/io/block.ts +10 -0
- package/src/styles/io/writer.ts +8 -3
- package/src/styles/plan/resolve.ts +14 -2
- package/src/styles/types.ts +28 -2
- package/src/styles/vocabulary.ts +15 -1
- package/src/types.ts +19 -5
- package/dist/chunks/block-DiGq58c3.js.map +0 -1
- package/dist/chunks/emit-CwU8cUmG.js.map +0 -1
- package/dist/chunks/export-BvqAXCKh.js.map +0 -1
- package/dist/chunks/format-BpQBx8MZ.js.map +0 -1
- package/dist/chunks/importer-BSvfrX_h.js.map +0 -1
- package/dist/chunks/importer-CMmeMWlC.js.map +0 -1
- package/dist/chunks/importer-COTK9Tsl.js.map +0 -1
- package/dist/chunks/importer-DiZRmOQG.js.map +0 -1
- package/dist/chunks/importer-e6LGpqHB.js.map +0 -1
- package/dist/chunks/lexicon-CT69Kd87.js.map +0 -1
- package/dist/chunks/styles-BQnsga7p.js.map +0 -1
- package/dist/chunks/styles-D3fRphrO.js.map +0 -1
- package/dist/chunks/styles-yed-BF5x3_Y5.js.map +0 -1
- package/dist/chunks/writer-DMKvthQE.js.map +0 -1
|
@@ -0,0 +1,793 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Running a source (design sections 2, 3 and 5): the checks before any request, the three read
|
|
3
|
+
* paths (`records` through the record methods, `file` through the format importers, `import`
|
|
4
|
+
* straight into the sink), the caps between pages, `idPrefix`, the versioned cursor, and the
|
|
5
|
+
* report's `source` member. graph-io keeps no state between calls.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { type GraphSink, INVALID_INDEX, type NodeId, type U32 } from "@graphty/graph-format";
|
|
9
|
+
|
|
10
|
+
import { MISSING_ID_CODE } from "../common/codes.js";
|
|
11
|
+
import { readBytes, throwIfAborted } from "../common/input.js";
|
|
12
|
+
import { ImportReportBuilder } from "../common/report.js";
|
|
13
|
+
import { readZipDirectory, readZipEntry } from "../common/zip.js";
|
|
14
|
+
import { type FormatRegistry } from "../registry.js";
|
|
15
|
+
import { SNIFF_HEAD_BYTES } from "../sniff.js";
|
|
16
|
+
import { type CommonImportOptions, ImportError, type ImportInput, type ImportReport } from "../types.js";
|
|
17
|
+
import { type CreatedContext, createSourceContext, detectRuntime, LimitStop } from "./context.js";
|
|
18
|
+
import { originOf } from "./credentials.js";
|
|
19
|
+
import { checkParams } from "./define.js";
|
|
20
|
+
import { failOn, warnOn } from "./fail.js";
|
|
21
|
+
import { SOURCE_FORMAT_PREFIX } from "./ids.js";
|
|
22
|
+
import {
|
|
23
|
+
type GraphSource,
|
|
24
|
+
type LoadFromSourceOptions,
|
|
25
|
+
type RecordBatch,
|
|
26
|
+
type SourceCursor,
|
|
27
|
+
type SourceFile,
|
|
28
|
+
} from "./types.js";
|
|
29
|
+
|
|
30
|
+
/** The cursor key graph-io adds, holding the source's descriptor version. */
|
|
31
|
+
const CURSOR_VERSION_KEY = "~v";
|
|
32
|
+
|
|
33
|
+
/** The options that belong to the source functions, never to an importer. */
|
|
34
|
+
const SOURCE_OPTION_KEYS: ReadonlySet<string> = new Set([
|
|
35
|
+
"endpoint",
|
|
36
|
+
"credential",
|
|
37
|
+
"cursor",
|
|
38
|
+
"limits",
|
|
39
|
+
"retry",
|
|
40
|
+
"idPrefix",
|
|
41
|
+
"allowInsecure",
|
|
42
|
+
"fetch",
|
|
43
|
+
"userAgent",
|
|
44
|
+
"builder",
|
|
45
|
+
"freeze",
|
|
46
|
+
"onProgress",
|
|
47
|
+
"signal",
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
/** The statuses whose failure on a later page keeps the pages before it. */
|
|
51
|
+
const AUTH_CODES: ReadonlySet<string> = new Set(["E_SOURCE_AUTH", "E_SOURCE_FORBIDDEN"]);
|
|
52
|
+
|
|
53
|
+
/** What a call needs set up before the source runs. */
|
|
54
|
+
interface Prepared {
|
|
55
|
+
/** The load's report. */
|
|
56
|
+
readonly report: ImportReportBuilder;
|
|
57
|
+
/** The context and its controls. */
|
|
58
|
+
readonly created: CreatedContext;
|
|
59
|
+
/** The params with the descriptor's defaults. */
|
|
60
|
+
readonly params: Record<string, unknown>;
|
|
61
|
+
/** The sink wrapper's counters, set once the sink is known. */
|
|
62
|
+
readonly counts: { nodes: Set<number>; edgesAtStart: number; sink: GraphSink | null };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The report format name of a source load.
|
|
67
|
+
* @param id - the source id
|
|
68
|
+
* @returns `"source:<id>"`
|
|
69
|
+
*/
|
|
70
|
+
export function sourceFormat(id: string): string {
|
|
71
|
+
return `${SOURCE_FORMAT_PREFIX}${id}`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The cursor handed back to the caller: the source's own, with its version added.
|
|
76
|
+
* @param next - the source's cursor
|
|
77
|
+
* @param version - the descriptor version
|
|
78
|
+
* @returns the caller's cursor
|
|
79
|
+
*/
|
|
80
|
+
export function wrapCursor(next: SourceCursor | null | undefined, version: number): SourceCursor | null {
|
|
81
|
+
return next === null || next === undefined ? null : Object.freeze({ ...next, [CURSOR_VERSION_KEY]: version });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Check every rule that holds before a request is sent and build the context.
|
|
86
|
+
* @param source - the loaded source
|
|
87
|
+
* @param rawParams - the caller's params
|
|
88
|
+
* @param options - the caller's options
|
|
89
|
+
* @param unit - what progress counts
|
|
90
|
+
* @returns the report, context and params
|
|
91
|
+
*/
|
|
92
|
+
function prepare(
|
|
93
|
+
source: GraphSource<never>,
|
|
94
|
+
rawParams: Readonly<Record<string, unknown>>,
|
|
95
|
+
options: LoadFromSourceOptions,
|
|
96
|
+
unit: "items" | "bytes",
|
|
97
|
+
): Prepared {
|
|
98
|
+
const { descriptor } = source;
|
|
99
|
+
const version = descriptor?.version ?? 1;
|
|
100
|
+
const report = new ImportReportBuilder(sourceFormat(source.id), options.errorLimit ?? 100);
|
|
101
|
+
checkRuntime(source, report);
|
|
102
|
+
checkParams(rawParams, descriptor, report);
|
|
103
|
+
const params: Record<string, unknown> = {};
|
|
104
|
+
for (const p of descriptor?.params ?? []) {
|
|
105
|
+
if (p.default !== undefined) {
|
|
106
|
+
params[p.name] = p.default;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
Object.assign(params, rawParams);
|
|
110
|
+
|
|
111
|
+
const endpoint = resolveEndpoint(options.endpoint ?? descriptor?.defaultEndpoint ?? null, report);
|
|
112
|
+
if (options.credential?.origins.length === 0 && endpoint === null) {
|
|
113
|
+
failOn(report, "E_SOURCE_PARAM", "a credential needs an endpoint or its own origins", {
|
|
114
|
+
name: "credential",
|
|
115
|
+
reason: "credential-unbound",
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
const cursor = resumeCursor(options.cursor, version, report);
|
|
119
|
+
|
|
120
|
+
const counts: Prepared["counts"] = { nodes: new Set<number>(), edgesAtStart: 0, sink: null };
|
|
121
|
+
const created = createSourceContext({
|
|
122
|
+
id: source.id,
|
|
123
|
+
descriptor,
|
|
124
|
+
options,
|
|
125
|
+
report,
|
|
126
|
+
endpoint,
|
|
127
|
+
cursor,
|
|
128
|
+
unit,
|
|
129
|
+
counts: () => ({
|
|
130
|
+
nodes: counts.nodes.size,
|
|
131
|
+
edges: counts.sink === null ? 0 : counts.sink.edgeCount - counts.edgesAtStart,
|
|
132
|
+
}),
|
|
133
|
+
});
|
|
134
|
+
return { report, created, params, counts };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Refuse a source that cannot run here: a runtime it does not support, or a secure context it needs.
|
|
139
|
+
* @param source - the loaded source
|
|
140
|
+
* @param report - the load's report
|
|
141
|
+
*/
|
|
142
|
+
function checkRuntime(source: GraphSource<never>, report: ImportReportBuilder): void {
|
|
143
|
+
const { descriptor } = source;
|
|
144
|
+
const runtime = detectRuntime();
|
|
145
|
+
const support = descriptor?.runtimes?.[runtime];
|
|
146
|
+
if (support?.supported === false) {
|
|
147
|
+
failOn(report, "E_SOURCE_RUNTIME", `source ${source.id} cannot run in ${runtime}`, {
|
|
148
|
+
runtime,
|
|
149
|
+
reason: support.reason ?? "unsupported",
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
if (
|
|
153
|
+
descriptor?.needs?.secureContext === true &&
|
|
154
|
+
runtime === "browser" &&
|
|
155
|
+
(globalThis as { isSecureContext?: boolean }).isSecureContext === false
|
|
156
|
+
) {
|
|
157
|
+
failOn(report, "E_SOURCE_RUNTIME", `source ${source.id} needs a secure context`, {
|
|
158
|
+
runtime,
|
|
159
|
+
reason: "needs-secure-context",
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* The endpoint as a URL, refusing one that is not a URL or carries a user name or password.
|
|
166
|
+
* @param given - the endpoint given, if any
|
|
167
|
+
* @param report - the load's report
|
|
168
|
+
* @returns the URL, or null without one
|
|
169
|
+
*/
|
|
170
|
+
function resolveEndpoint(given: string | URL | null, report: ImportReportBuilder): URL | null {
|
|
171
|
+
if (given === null) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
let endpoint: URL;
|
|
175
|
+
try {
|
|
176
|
+
endpoint = new URL(given);
|
|
177
|
+
} catch {
|
|
178
|
+
failOn(report, "E_SOURCE_PARAM", "the endpoint is not a URL", { name: "endpoint", reason: "type" });
|
|
179
|
+
}
|
|
180
|
+
if (endpoint.username !== "" || endpoint.password !== "") {
|
|
181
|
+
failOn(report, "E_SOURCE_PARAM", "the endpoint may not carry a user name or password", {
|
|
182
|
+
name: "endpoint",
|
|
183
|
+
reason: "credentials-in-url",
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return endpoint;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* The source's own cursor from the caller's, refusing one another descriptor version made.
|
|
191
|
+
* @param given - the caller's cursor, if any
|
|
192
|
+
* @param version - the descriptor version
|
|
193
|
+
* @param report - the load's report
|
|
194
|
+
* @returns the source's cursor, or null
|
|
195
|
+
*/
|
|
196
|
+
function resumeCursor(
|
|
197
|
+
given: SourceCursor | null | undefined,
|
|
198
|
+
version: number,
|
|
199
|
+
report: ImportReportBuilder,
|
|
200
|
+
): SourceCursor | null {
|
|
201
|
+
if (given === undefined || given === null) {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
const { [CURSOR_VERSION_KEY]: recorded, ...rest } = given;
|
|
205
|
+
if (recorded !== undefined && recorded !== version) {
|
|
206
|
+
failOn(report, "E_SOURCE_PARAM", "the cursor was made by another version of the source", {
|
|
207
|
+
name: "cursor",
|
|
208
|
+
reason: "stale-cursor",
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return Object.freeze(rest);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Wrap a sink so every node id gets the prefix and the caps can count the distinct nodes written.
|
|
216
|
+
* @param sink - the caller's sink or the builder
|
|
217
|
+
* @param prepared - the call's counters
|
|
218
|
+
* @param prefix - the idPrefix, if any
|
|
219
|
+
* @returns the wrapped sink
|
|
220
|
+
*/
|
|
221
|
+
export function wrapSink(sink: GraphSink, prepared: Prepared, prefix: string | undefined): GraphSink {
|
|
222
|
+
prepared.counts.sink = sink;
|
|
223
|
+
prepared.counts.edgesAtStart = sink.edgeCount;
|
|
224
|
+
const seen = prepared.counts.nodes;
|
|
225
|
+
const id = (value: NodeId): NodeId => (prefix === undefined || prefix === "" ? value : `${prefix}${String(value)}`);
|
|
226
|
+
const node = (index: number): number => {
|
|
227
|
+
seen.add(index);
|
|
228
|
+
return index;
|
|
229
|
+
};
|
|
230
|
+
// an edge may add its end nodes (addMissingNodes)
|
|
231
|
+
const ends = (edge: number): number => {
|
|
232
|
+
const [a, b] = sink.edgeEndpoints(edge);
|
|
233
|
+
seen.add(a);
|
|
234
|
+
seen.add(b);
|
|
235
|
+
return edge;
|
|
236
|
+
};
|
|
237
|
+
return new Proxy(sink, {
|
|
238
|
+
get(target, key): unknown {
|
|
239
|
+
switch (key) {
|
|
240
|
+
case "addNode":
|
|
241
|
+
return (v: NodeId): number => node(target.addNode(id(v)));
|
|
242
|
+
case "addNodeRecord":
|
|
243
|
+
return (v: NodeId, attrs: Readonly<Record<string, unknown>>): number =>
|
|
244
|
+
node(target.addNodeRecord(id(v), attrs));
|
|
245
|
+
case "addNodes":
|
|
246
|
+
return (ids: Iterable<NodeId>, out?: U32): U32 => {
|
|
247
|
+
const result = target.addNodes(Array.from(ids, id), out);
|
|
248
|
+
result.forEach((i) => seen.add(i));
|
|
249
|
+
return result;
|
|
250
|
+
};
|
|
251
|
+
case "addEdge":
|
|
252
|
+
return (s: NodeId, t: NodeId, w?: number): number => ends(target.addEdge(id(s), id(t), w));
|
|
253
|
+
case "addEdgeRecord":
|
|
254
|
+
return (
|
|
255
|
+
s: NodeId,
|
|
256
|
+
t: NodeId,
|
|
257
|
+
attrs: Readonly<Record<string, unknown>>,
|
|
258
|
+
weightKey?: string | null,
|
|
259
|
+
): number => ends(target.addEdgeRecord(id(s), id(t), attrs, weightKey));
|
|
260
|
+
case "indexOf":
|
|
261
|
+
return (v: NodeId): number => target.indexOf(id(v));
|
|
262
|
+
default: {
|
|
263
|
+
const value = Reflect.get(target, key, target) as unknown;
|
|
264
|
+
return typeof value === "function" ? (value as (...a: unknown[]) => unknown).bind(target) : value;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* The options a format importer gets from a file source's load.
|
|
273
|
+
* @param options - the caller's options
|
|
274
|
+
* @param signal - the context's signal
|
|
275
|
+
* @returns the importer options
|
|
276
|
+
*/
|
|
277
|
+
function importerOptions(options: LoadFromSourceOptions, signal: AbortSignal): CommonImportOptions {
|
|
278
|
+
const out: Record<string, unknown> = { signal };
|
|
279
|
+
for (const [key, value] of Object.entries(options)) {
|
|
280
|
+
if (!SOURCE_OPTION_KEYS.has(key)) {
|
|
281
|
+
out[key] = value;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return out;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Write graph facts: `name`, `description` and `modified` strings to the graph's meta, any other
|
|
289
|
+
* scalar (but `directed`) as a graph value.
|
|
290
|
+
* @param sink - the sink
|
|
291
|
+
* @param meta - the facts
|
|
292
|
+
*/
|
|
293
|
+
function writeMeta(sink: GraphSink, meta: Readonly<Record<string, unknown>>): void {
|
|
294
|
+
const patch: Record<string, string> = {};
|
|
295
|
+
for (const [key, value] of Object.entries(meta)) {
|
|
296
|
+
if ((key === "name" || key === "description" || key === "modified") && typeof value === "string") {
|
|
297
|
+
patch[key] = value;
|
|
298
|
+
} else if (
|
|
299
|
+
key !== "directed" &&
|
|
300
|
+
(typeof value === "string" || typeof value === "number" || typeof value === "boolean")
|
|
301
|
+
) {
|
|
302
|
+
sink.setGraphValue(key, value);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (Object.keys(patch).length > 0) {
|
|
306
|
+
sink.setMeta(patch);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Write one page of records into the sink.
|
|
312
|
+
* @param batch - the page
|
|
313
|
+
* @param sink - the wrapped sink
|
|
314
|
+
* @param source - the source (for its record keys)
|
|
315
|
+
* @param prepared - the call
|
|
316
|
+
* @param first - whether this is the first page
|
|
317
|
+
*/
|
|
318
|
+
function writeBatch(
|
|
319
|
+
batch: RecordBatch,
|
|
320
|
+
sink: GraphSink,
|
|
321
|
+
source: GraphSource<never>,
|
|
322
|
+
prepared: Prepared,
|
|
323
|
+
first: boolean,
|
|
324
|
+
): void {
|
|
325
|
+
const idKey = source.idKey ?? "id";
|
|
326
|
+
const sourceKey = source.sourceKey ?? "source";
|
|
327
|
+
const targetKey = source.targetKey ?? "target";
|
|
328
|
+
const meta = batch.meta ?? {};
|
|
329
|
+
if (first && typeof meta.directed === "boolean" && sink.edgeCount === 0) {
|
|
330
|
+
sink.setDirected(meta.directed);
|
|
331
|
+
}
|
|
332
|
+
writeMeta(sink, meta);
|
|
333
|
+
const n = writeNodes(batch, sink, idKey, prepared);
|
|
334
|
+
writeEdges(batch, sink, sourceKey, targetKey, prepared, n);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Write a page's node records.
|
|
339
|
+
* @param batch - the page
|
|
340
|
+
* @param sink - the wrapped sink
|
|
341
|
+
* @param idKey - the record key holding the id
|
|
342
|
+
* @param prepared - the call
|
|
343
|
+
* @returns how many records were visited, for the abort check's cadence
|
|
344
|
+
*/
|
|
345
|
+
function writeNodes(batch: RecordBatch, sink: GraphSink, idKey: string, prepared: Prepared): number {
|
|
346
|
+
const { report } = prepared;
|
|
347
|
+
const { signal } = prepared.created.ctx;
|
|
348
|
+
let n = 0;
|
|
349
|
+
for (const record of batch.nodes ?? []) {
|
|
350
|
+
if (n++ % 64 === 0) {
|
|
351
|
+
throwIfAborted(signal);
|
|
352
|
+
}
|
|
353
|
+
const { [idKey]: id, ...attrs } = record;
|
|
354
|
+
if (typeof id !== "string" && typeof id !== "number") {
|
|
355
|
+
report.error("missing-value", MISSING_ID_CODE, `a node record has no ${idKey}`);
|
|
356
|
+
report.counts.skippedNodes++;
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
try {
|
|
360
|
+
sink.addNodeRecord(id, attrs);
|
|
361
|
+
report.counts.nodes++;
|
|
362
|
+
} catch (err) {
|
|
363
|
+
report.recordError(err, { element: String(id) });
|
|
364
|
+
report.counts.skippedNodes++;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return n;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Write a page's edge records.
|
|
372
|
+
* @param batch - the page
|
|
373
|
+
* @param sink - the wrapped sink
|
|
374
|
+
* @param sourceKey - the record key holding the source id
|
|
375
|
+
* @param targetKey - the record key holding the target id
|
|
376
|
+
* @param prepared - the call
|
|
377
|
+
* @param start - records visited so far, for the abort check's cadence
|
|
378
|
+
*/
|
|
379
|
+
function writeEdges(
|
|
380
|
+
batch: RecordBatch,
|
|
381
|
+
sink: GraphSink,
|
|
382
|
+
sourceKey: string,
|
|
383
|
+
targetKey: string,
|
|
384
|
+
prepared: Prepared,
|
|
385
|
+
start: number,
|
|
386
|
+
): void {
|
|
387
|
+
const { report } = prepared;
|
|
388
|
+
const { signal } = prepared.created.ctx;
|
|
389
|
+
let n = start;
|
|
390
|
+
let edgeIds: ReturnType<GraphSink["declareEdgeColumn"]> | null = null;
|
|
391
|
+
for (const record of batch.edges ?? []) {
|
|
392
|
+
if (n++ % 64 === 0) {
|
|
393
|
+
throwIfAborted(signal);
|
|
394
|
+
}
|
|
395
|
+
const s = record[sourceKey];
|
|
396
|
+
const t = record[targetKey];
|
|
397
|
+
const edgeId = record.id;
|
|
398
|
+
const fields = Object.fromEntries(
|
|
399
|
+
Object.entries(record).filter(([k]) => k !== sourceKey && k !== targetKey && k !== "id"),
|
|
400
|
+
);
|
|
401
|
+
if ((typeof s !== "string" && typeof s !== "number") || (typeof t !== "string" && typeof t !== "number")) {
|
|
402
|
+
report.error("missing-value", MISSING_ID_CODE, `an edge record has no ${sourceKey} or ${targetKey}`);
|
|
403
|
+
report.counts.skippedEdges++;
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
try {
|
|
407
|
+
const e = sink.addEdgeRecord(s, t, fields);
|
|
408
|
+
if (typeof edgeId === "string" || typeof edgeId === "number") {
|
|
409
|
+
edgeIds ??= edgeIdColumn(sink);
|
|
410
|
+
sink.setEdgeValue(edgeIds, e, String(edgeId));
|
|
411
|
+
}
|
|
412
|
+
report.counts.edges++;
|
|
413
|
+
} catch (err) {
|
|
414
|
+
report.recordError(err, { element: `${String(s)} -> ${String(t)}` });
|
|
415
|
+
report.counts.skippedEdges++;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* The origin of an endpoint, or "" without one.
|
|
422
|
+
* @param endpoint - the endpoint
|
|
423
|
+
* @returns its origin
|
|
424
|
+
*/
|
|
425
|
+
function endpointOrigin(endpoint: URL | null): string {
|
|
426
|
+
return endpoint === null ? "" : originOf(endpoint);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* The edge id column, declared on first use.
|
|
431
|
+
* @param sink - the sink
|
|
432
|
+
* @returns its handle
|
|
433
|
+
*/
|
|
434
|
+
function edgeIdColumn(sink: GraphSink): ReturnType<GraphSink["declareEdgeColumn"]> {
|
|
435
|
+
const existing = sink.edgeColumn("id");
|
|
436
|
+
return existing === INVALID_INDEX
|
|
437
|
+
? sink.declareEdgeColumn({ name: "id", dtype: "string", role: "id", nullable: true })
|
|
438
|
+
: existing;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* The page iterator of a records source: its async iterable, or its one batch.
|
|
443
|
+
* @param out - what `records()` returned
|
|
444
|
+
* @returns an iterator over the pages
|
|
445
|
+
*/
|
|
446
|
+
function pages(out: Promise<RecordBatch> | AsyncIterable<RecordBatch>): AsyncIterator<RecordBatch> {
|
|
447
|
+
if (Symbol.asyncIterator in out) {
|
|
448
|
+
return out[Symbol.asyncIterator]();
|
|
449
|
+
}
|
|
450
|
+
let done = false;
|
|
451
|
+
return {
|
|
452
|
+
async next(): Promise<IteratorResult<RecordBatch>> {
|
|
453
|
+
if (done) {
|
|
454
|
+
return { done: true, value: undefined };
|
|
455
|
+
}
|
|
456
|
+
done = true;
|
|
457
|
+
return { done: false, value: await out };
|
|
458
|
+
},
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Decide what a failed page means: a cap reached or a later page needing a credential stops the
|
|
464
|
+
* load and keeps what was read (warning for the credential); anything else is rethrown.
|
|
465
|
+
* @param err - what the page threw
|
|
466
|
+
* @param page - how many pages were written before it
|
|
467
|
+
* @param prepared - the call
|
|
468
|
+
*/
|
|
469
|
+
function stopOrThrow(err: unknown, page: number, prepared: Prepared): void {
|
|
470
|
+
if (err instanceof LimitStop) {
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
if (page > 0 && err instanceof ImportError && AUTH_CODES.has(String(err.issue?.code))) {
|
|
474
|
+
const p = err.issue?.params ?? {};
|
|
475
|
+
warnOn(prepared.report, "W_SOURCE_AUTH", "a later page needs a credential; the pages before it are kept", {
|
|
476
|
+
origin: typeof p.origin === "string" ? p.origin : endpointOrigin(prepared.created.ctx.endpoint),
|
|
477
|
+
status: typeof p.status === "number" ? p.status : null,
|
|
478
|
+
});
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
throw err;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Run a records source into a sink.
|
|
486
|
+
* @param source - the source
|
|
487
|
+
* @param sink - the wrapped sink
|
|
488
|
+
* @param prepared - the call
|
|
489
|
+
* @returns where to resume, as the source gave it
|
|
490
|
+
*/
|
|
491
|
+
async function runRecords(
|
|
492
|
+
source: GraphSource<never>,
|
|
493
|
+
sink: GraphSink,
|
|
494
|
+
prepared: Prepared,
|
|
495
|
+
): Promise<SourceCursor | null> {
|
|
496
|
+
const { ctx } = prepared.created;
|
|
497
|
+
const records = source.records as (p: unknown, c: typeof ctx) => Promise<RecordBatch> | AsyncIterable<RecordBatch>;
|
|
498
|
+
const iterator = pages(records(prepared.params, ctx));
|
|
499
|
+
let next: SourceCursor | null = ctx.cursor;
|
|
500
|
+
let page = 0;
|
|
501
|
+
let stopped = false;
|
|
502
|
+
try {
|
|
503
|
+
for (;;) {
|
|
504
|
+
let step: IteratorResult<RecordBatch>;
|
|
505
|
+
try {
|
|
506
|
+
step = await iterator.next();
|
|
507
|
+
} catch (err) {
|
|
508
|
+
stopOrThrow(err, page, prepared);
|
|
509
|
+
stopped = true;
|
|
510
|
+
return next;
|
|
511
|
+
}
|
|
512
|
+
if (step.done === true) {
|
|
513
|
+
return page === 0 ? null : next;
|
|
514
|
+
}
|
|
515
|
+
writeBatch(step.value, sink, source, prepared, page === 0);
|
|
516
|
+
page++;
|
|
517
|
+
next = step.value.next ?? null;
|
|
518
|
+
ctx.progress(prepared.report.counts.nodes + prepared.report.counts.edges, undefined, "items");
|
|
519
|
+
if (ctx.limits.reached()) {
|
|
520
|
+
stopped = true;
|
|
521
|
+
return next;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
} finally {
|
|
525
|
+
if (stopped) {
|
|
526
|
+
await iterator.return?.().catch(() => undefined);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* The importer input of a file source's body, gunzipped or unzipped when its name says so.
|
|
533
|
+
* @param file - what the source returned
|
|
534
|
+
* @param formats - the registry, for choosing a zip entry
|
|
535
|
+
* @param signal - the signal
|
|
536
|
+
* @returns the input and its hints
|
|
537
|
+
*/
|
|
538
|
+
async function fileInput(
|
|
539
|
+
file: SourceFile,
|
|
540
|
+
formats: FormatRegistry,
|
|
541
|
+
signal: AbortSignal,
|
|
542
|
+
): Promise<{ input: ImportInput; filename: string | undefined; mimeType: string | undefined }> {
|
|
543
|
+
let input: ImportInput = file.body instanceof Response ? (file.body.body ?? new Uint8Array(0)) : file.body;
|
|
544
|
+
let { filename } = file;
|
|
545
|
+
let mimeType =
|
|
546
|
+
file.mimeType ??
|
|
547
|
+
(file.body instanceof Response ? (file.body.headers.get("content-type") ?? undefined) : undefined);
|
|
548
|
+
const gzip = /\.gz$/i.test(filename ?? "") || /gzip/i.test(mimeType ?? "");
|
|
549
|
+
const zip = /\.zip$/i.test(filename ?? "") || /\/(x-)?zip\b/i.test(mimeType ?? "");
|
|
550
|
+
if (gzip) {
|
|
551
|
+
const stream =
|
|
552
|
+
input instanceof ReadableStream
|
|
553
|
+
? input
|
|
554
|
+
: new Response((await bytesOf(input, signal)) as Uint8Array<ArrayBuffer>).body;
|
|
555
|
+
input = (stream ?? new Response("").body ?? new ReadableStream()).pipeThrough(
|
|
556
|
+
new DecompressionStream("gzip") as unknown as ReadableWritablePair<Uint8Array, Uint8Array>,
|
|
557
|
+
);
|
|
558
|
+
filename = filename?.replace(/\.gz$/i, "");
|
|
559
|
+
mimeType = undefined;
|
|
560
|
+
} else if (zip) {
|
|
561
|
+
const bytes = await bytesOf(input, signal);
|
|
562
|
+
const entry = readZipDirectory(bytes).find((e) => !e.directory && formats.sniff({ filename: e.name }) !== null);
|
|
563
|
+
if (entry === undefined) {
|
|
564
|
+
throw new ImportError("the zip holds no graph file", new ImportReportBuilder("zip", 0).finish());
|
|
565
|
+
}
|
|
566
|
+
input = await readZipEntry(bytes, entry, { signal, maxBytes: Number.MAX_SAFE_INTEGER, maxRatio: 1000 });
|
|
567
|
+
filename = entry.name;
|
|
568
|
+
mimeType = undefined;
|
|
569
|
+
}
|
|
570
|
+
return { input, filename, mimeType };
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* The bytes of an input.
|
|
575
|
+
* @param input - the input
|
|
576
|
+
* @param signal - the signal
|
|
577
|
+
* @returns the bytes
|
|
578
|
+
*/
|
|
579
|
+
async function bytesOf(input: ImportInput, signal: AbortSignal): Promise<Uint8Array> {
|
|
580
|
+
return (await readBytes(input, { signal })) ?? new TextEncoder().encode(typeof input === "string" ? input : "");
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Run a file source into a sink through the format importers.
|
|
585
|
+
* @param source - the source
|
|
586
|
+
* @param sink - the wrapped sink
|
|
587
|
+
* @param prepared - the call
|
|
588
|
+
* @param formats - the registry
|
|
589
|
+
* @param options - the caller's options
|
|
590
|
+
* @returns the format the file was read as
|
|
591
|
+
*/
|
|
592
|
+
async function runFile(
|
|
593
|
+
source: GraphSource<never>,
|
|
594
|
+
sink: GraphSink,
|
|
595
|
+
prepared: Prepared,
|
|
596
|
+
formats: FormatRegistry,
|
|
597
|
+
options: LoadFromSourceOptions,
|
|
598
|
+
): Promise<string> {
|
|
599
|
+
const { ctx } = prepared.created;
|
|
600
|
+
const read = source.file as (p: unknown, c: typeof ctx) => Promise<SourceFile>;
|
|
601
|
+
const file = await read(prepared.params, ctx);
|
|
602
|
+
const { input, filename, mimeType } = await fileInput(file, formats, ctx.signal);
|
|
603
|
+
let { format } = file;
|
|
604
|
+
let body: ImportInput = input;
|
|
605
|
+
if (format === undefined) {
|
|
606
|
+
const bytes = await bytesOf(input, ctx.signal);
|
|
607
|
+
format = formats.sniff({ filename, mimeType, head: bytes.subarray(0, SNIFF_HEAD_BYTES) })?.format;
|
|
608
|
+
body = bytes;
|
|
609
|
+
if (format === undefined) {
|
|
610
|
+
failOn(prepared.report, "E_SOURCE_RESPONSE", "the file is in no format graph-io reads", {
|
|
611
|
+
expected: "graph-file",
|
|
612
|
+
contentType: mimeType ?? null,
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
const importer = formats.importer(format);
|
|
617
|
+
prepared.report.include(await importer.import(body, sink, importerOptions(options, ctx.signal)));
|
|
618
|
+
writeMeta(sink, file.meta ?? {});
|
|
619
|
+
return format;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/** What a run into a sink produced. */
|
|
623
|
+
interface SinkRun {
|
|
624
|
+
/** The report, with its `source` member. */
|
|
625
|
+
readonly report: ImportReport;
|
|
626
|
+
/** The format: `source:<id>`, or the format a file source resolved to. */
|
|
627
|
+
readonly format: string;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Run a source's read method into a sink.
|
|
632
|
+
* @param source - the loaded source
|
|
633
|
+
* @param params - the caller's params
|
|
634
|
+
* @param sink - where to write
|
|
635
|
+
* @param options - the caller's options
|
|
636
|
+
* @param formats - the registry, for file sources
|
|
637
|
+
* @returns the report and the format
|
|
638
|
+
*/
|
|
639
|
+
export async function runIntoSink(
|
|
640
|
+
source: GraphSource<never>,
|
|
641
|
+
params: Readonly<Record<string, unknown>>,
|
|
642
|
+
sink: GraphSink,
|
|
643
|
+
options: LoadFromSourceOptions,
|
|
644
|
+
formats: FormatRegistry,
|
|
645
|
+
): Promise<SinkRun> {
|
|
646
|
+
const prepared = prepare(source, params, options, typeof source.file === "function" ? "bytes" : "items");
|
|
647
|
+
const { ctx } = prepared.created;
|
|
648
|
+
const version = source.descriptor?.version ?? 1;
|
|
649
|
+
const wrapped = wrapSink(sink, prepared, options.idPrefix);
|
|
650
|
+
try {
|
|
651
|
+
if (typeof source.records === "function") {
|
|
652
|
+
const next = await runRecords(source, wrapped, prepared);
|
|
653
|
+
throwIfAborted(ctx.signal);
|
|
654
|
+
return {
|
|
655
|
+
report: withSource(prepared.report.finish(), prepared, wrapCursor(next, version)),
|
|
656
|
+
format: sourceFormat(source.id),
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
if (typeof source.file === "function") {
|
|
660
|
+
const format = await runFile(source, wrapped, prepared, formats, options);
|
|
661
|
+
return { report: withSource(prepared.report.finish(), prepared, null), format };
|
|
662
|
+
}
|
|
663
|
+
const run = source.import as (p: unknown, s: GraphSink, c: typeof ctx) => Promise<ImportReport>;
|
|
664
|
+
const report = await stopAtLimit(run(prepared.params, wrapped, ctx), prepared);
|
|
665
|
+
throwIfAborted(ctx.signal);
|
|
666
|
+
return {
|
|
667
|
+
report: withSource(report, prepared, wrapCursor(prepared.created.state.finish?.next, version)),
|
|
668
|
+
format: sourceFormat(source.id),
|
|
669
|
+
};
|
|
670
|
+
} catch (err) {
|
|
671
|
+
throw settle(err, prepared);
|
|
672
|
+
} finally {
|
|
673
|
+
prepared.created.dispose();
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Run an optional method of a source (expand, probe, list, validate) with a context.
|
|
679
|
+
* @param source - the loaded source
|
|
680
|
+
* @param feature - the method name
|
|
681
|
+
* @param params - the params checked against the descriptor
|
|
682
|
+
* @param options - the caller's options
|
|
683
|
+
* @param call - calls the method with the context
|
|
684
|
+
* @returns what the method returned, and the call's state
|
|
685
|
+
*/
|
|
686
|
+
export async function runMethod<T>(
|
|
687
|
+
source: GraphSource<never>,
|
|
688
|
+
feature: "expand" | "probe" | "list" | "validate",
|
|
689
|
+
params: Readonly<Record<string, unknown>>,
|
|
690
|
+
options: LoadFromSourceOptions,
|
|
691
|
+
call: (prepared: Prepared) => Promise<T>,
|
|
692
|
+
): Promise<T> {
|
|
693
|
+
if (typeof source[feature] !== "function") {
|
|
694
|
+
failOn(
|
|
695
|
+
new ImportReportBuilder(sourceFormat(source.id), 0),
|
|
696
|
+
"E_SOURCE_UNSUPPORTED",
|
|
697
|
+
`source ${source.id} has no ${feature}`,
|
|
698
|
+
{
|
|
699
|
+
feature,
|
|
700
|
+
},
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
const prepared = prepare(source, params, options, "items");
|
|
704
|
+
try {
|
|
705
|
+
const out = await call(prepared);
|
|
706
|
+
throwIfAborted(prepared.created.ctx.signal);
|
|
707
|
+
return out;
|
|
708
|
+
} catch (err) {
|
|
709
|
+
throw settle(err, prepared);
|
|
710
|
+
} finally {
|
|
711
|
+
prepared.created.dispose();
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Add the `source` member to a report.
|
|
717
|
+
* @param report - the report
|
|
718
|
+
* @param prepared - the call
|
|
719
|
+
* @param next - where to resume, as the caller sees it
|
|
720
|
+
* @returns the report with its source member
|
|
721
|
+
*/
|
|
722
|
+
export function withSource(report: ImportReport, prepared: Prepared, next: SourceCursor | null): ImportReport {
|
|
723
|
+
const own = prepared.report.finish();
|
|
724
|
+
// issues the context recorded (retries, limits) that a source's own report does not hold
|
|
725
|
+
const missing = own.issues.filter((i) => !report.issues.includes(i));
|
|
726
|
+
return Object.freeze({
|
|
727
|
+
...report,
|
|
728
|
+
issues: missing.length === 0 ? report.issues : Object.freeze([...report.issues, ...missing]),
|
|
729
|
+
warningCount: report.warningCount + missing.filter((i) => i.severity === "warning").length,
|
|
730
|
+
errorCount: report.errorCount + missing.filter((i) => i.severity === "error").length,
|
|
731
|
+
source: prepared.created.info(next),
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* What a failed call throws: the signal's reason when it aborted, an ImportError with the source
|
|
737
|
+
* info attached, or the error itself.
|
|
738
|
+
* @param err - what was thrown
|
|
739
|
+
* @param prepared - the call
|
|
740
|
+
* @returns the error to throw
|
|
741
|
+
*/
|
|
742
|
+
function settle(err: unknown, prepared: Prepared): unknown {
|
|
743
|
+
const { signal } = prepared.created.ctx;
|
|
744
|
+
if (signal.aborted) {
|
|
745
|
+
return signal.reason as unknown;
|
|
746
|
+
}
|
|
747
|
+
if (err instanceof LimitStop) {
|
|
748
|
+
// a cap reached where nothing can be kept (a file cut short): the load fails with the cap
|
|
749
|
+
return settle(limitError(err, prepared), prepared);
|
|
750
|
+
}
|
|
751
|
+
if (err instanceof ImportError && err.report.source === undefined) {
|
|
752
|
+
const withInfo = new ImportError(
|
|
753
|
+
err.message,
|
|
754
|
+
{ ...err.report, source: prepared.created.info(null) },
|
|
755
|
+
err.details,
|
|
756
|
+
);
|
|
757
|
+
withInfo.stack = err.stack;
|
|
758
|
+
return withInfo;
|
|
759
|
+
}
|
|
760
|
+
return err;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* The E_SOURCE_LIMIT error of a cap that stopped a load which can keep nothing.
|
|
765
|
+
* @param stop - the cap reached
|
|
766
|
+
* @param prepared - the call
|
|
767
|
+
* @returns the error
|
|
768
|
+
*/
|
|
769
|
+
function limitError(stop: LimitStop, prepared: Prepared): unknown {
|
|
770
|
+
try {
|
|
771
|
+
return failOn(prepared.report, "E_SOURCE_LIMIT", stop.message, { limit: stop.limit, value: stop.value });
|
|
772
|
+
} catch (err) {
|
|
773
|
+
return err;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* The report of an import or expand source, or, when a cap stopped it under "stop" (a LimitStop
|
|
779
|
+
* raised by ctx.fetch that the source did not catch), the report of what it wrote so far.
|
|
780
|
+
* @param run - the source's call
|
|
781
|
+
* @param prepared - the call
|
|
782
|
+
* @returns the report
|
|
783
|
+
*/
|
|
784
|
+
export async function stopAtLimit(run: Promise<ImportReport>, prepared: Prepared): Promise<ImportReport> {
|
|
785
|
+
try {
|
|
786
|
+
return await run;
|
|
787
|
+
} catch (err) {
|
|
788
|
+
if (err instanceof LimitStop) {
|
|
789
|
+
return prepared.report.finish();
|
|
790
|
+
}
|
|
791
|
+
throw err;
|
|
792
|
+
}
|
|
793
|
+
}
|