@graphty/graph-io 0.3.47 → 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,1367 @@
|
|
|
1
|
+
import { R as REST_DESCRIPTOR, O as OPENALEX_DESCRIPTOR } from "./chunks/descriptor-BJ-W0Jd-.js";
|
|
2
|
+
import { D, S } from "./chunks/descriptor-BJ-W0Jd-.js";
|
|
3
|
+
import { f as failOn, S as SOURCE_ENTITY_ATTR, e as SOURCE_STUB_ATTR, d as defineSource, R as REST_SOURCE_ID, b as failAlone, o as originOf, w as warnOn, O as OPENALEX_SOURCE_ID } from "./chunks/credentials-BiQsnMTb.js";
|
|
4
|
+
import { b as throwIfAborted } from "./chunks/input-Ccg9I22A.js";
|
|
5
|
+
import { ah as ImportError } from "./chunks/report-CgdsL9Hb.js";
|
|
6
|
+
import { s as sleep } from "./chunks/context-cgmmOxZ2.js";
|
|
7
|
+
const STEP = /^([^.[\]]+)(\[\])?$/;
|
|
8
|
+
const PARSED = /* @__PURE__ */ new Map();
|
|
9
|
+
function parseSelector(selector) {
|
|
10
|
+
const cached = PARSED.get(selector);
|
|
11
|
+
if (cached !== void 0) {
|
|
12
|
+
return cached;
|
|
13
|
+
}
|
|
14
|
+
let steps = [];
|
|
15
|
+
if (selector !== ".") {
|
|
16
|
+
for (const part of selector.split(".")) {
|
|
17
|
+
const m = STEP.exec(part);
|
|
18
|
+
if (m === null) {
|
|
19
|
+
steps = null;
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
steps.push({ key: m[1], flatten: m[2] !== void 0 });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
PARSED.set(selector, steps);
|
|
26
|
+
return steps;
|
|
27
|
+
}
|
|
28
|
+
function select(value, selector) {
|
|
29
|
+
let out = value === void 0 ? [] : [value];
|
|
30
|
+
for (const step of parseSelector(selector) ?? []) {
|
|
31
|
+
const next = [];
|
|
32
|
+
for (const v of out) {
|
|
33
|
+
if (typeof v !== "object" || v === null || !Object.hasOwn(v, step.key)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const got = v[step.key];
|
|
37
|
+
if (step.flatten && Array.isArray(got)) {
|
|
38
|
+
next.push(...got);
|
|
39
|
+
} else if (got !== void 0 && got !== null) {
|
|
40
|
+
next.push(got);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
out = next;
|
|
44
|
+
}
|
|
45
|
+
return out.filter((v) => v !== null && v !== void 0);
|
|
46
|
+
}
|
|
47
|
+
function selectOne(value, selector) {
|
|
48
|
+
return select(value, selector)[0];
|
|
49
|
+
}
|
|
50
|
+
function selectRecords(body, selector) {
|
|
51
|
+
const out = select(body, selector);
|
|
52
|
+
return out.length === 1 && Array.isArray(out[0]) ? out[0] : out;
|
|
53
|
+
}
|
|
54
|
+
const SLOT = /\{([^{}]*)\}/g;
|
|
55
|
+
const NAME = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
56
|
+
function templateNames(template) {
|
|
57
|
+
const names = [];
|
|
58
|
+
for (const m of template.matchAll(SLOT)) {
|
|
59
|
+
if (!NAME.test(m[1])) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
names.push(m[1]);
|
|
63
|
+
}
|
|
64
|
+
return /[{}]/.test(template.replaceAll(SLOT, "")) ? null : names;
|
|
65
|
+
}
|
|
66
|
+
function fill(template, values, encode, report) {
|
|
67
|
+
return template.replaceAll(SLOT, (_, name) => {
|
|
68
|
+
const value = values[name];
|
|
69
|
+
if (value === void 0) {
|
|
70
|
+
failOn(report, "E_SOURCE_PARAM", `the mapping's template needs ${name}`, { name, reason: "required" });
|
|
71
|
+
}
|
|
72
|
+
return encode(value);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function pathValue(report) {
|
|
76
|
+
return (value) => {
|
|
77
|
+
if (value === "." || value === ".." || value === "") {
|
|
78
|
+
failOn(report, "E_SOURCE_PARAM", "a path value may not be empty or a dot segment", {
|
|
79
|
+
name: "path",
|
|
80
|
+
reason: "path"
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return encodeURIComponent(value);
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function checkOrigin(url, endpoint, report) {
|
|
87
|
+
const base = endpoint.pathname.replace(/\/$/, "");
|
|
88
|
+
if (url.origin !== endpoint.origin || !(url.pathname === base || url.pathname.startsWith(`${base}/`))) {
|
|
89
|
+
failOn(report, "E_SOURCE_PARAM", "a request left the mapping's endpoint", { name: "url", reason: "origin" });
|
|
90
|
+
}
|
|
91
|
+
return url;
|
|
92
|
+
}
|
|
93
|
+
function buildRequest(endpoint, request, values, report) {
|
|
94
|
+
const path = fill(request.path, values, pathValue(report), report);
|
|
95
|
+
const url = new URL(`${endpoint.origin}${endpoint.pathname.replace(/\/$/, "")}${path}`);
|
|
96
|
+
for (const [key, template] of Object.entries(request.query ?? {})) {
|
|
97
|
+
url.searchParams.set(
|
|
98
|
+
key,
|
|
99
|
+
fill(template, values, (v) => v, report)
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
checkOrigin(url, endpoint, report);
|
|
103
|
+
if (request.method !== "POST") {
|
|
104
|
+
return { url, init: {} };
|
|
105
|
+
}
|
|
106
|
+
const body = fillBody(request.body, values, report);
|
|
107
|
+
return {
|
|
108
|
+
url,
|
|
109
|
+
init: {
|
|
110
|
+
method: "POST",
|
|
111
|
+
headers: { "content-type": "application/json" },
|
|
112
|
+
body: JSON.stringify(body ?? null),
|
|
113
|
+
// a mapping's POST reads; it is a query, so it is as safe to retry as a GET
|
|
114
|
+
idempotent: true
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function fillBody(body, values, report) {
|
|
119
|
+
if (typeof body === "string") {
|
|
120
|
+
return fill(body, values, (v) => v, report);
|
|
121
|
+
}
|
|
122
|
+
if (Array.isArray(body)) {
|
|
123
|
+
return body.map((b) => fillBody(b, values, report));
|
|
124
|
+
}
|
|
125
|
+
if (typeof body === "object" && body !== null) {
|
|
126
|
+
return Object.fromEntries(Object.entries(body).map(([k, v]) => [k, fillBody(v, values, report)]));
|
|
127
|
+
}
|
|
128
|
+
return body;
|
|
129
|
+
}
|
|
130
|
+
function isObject(v) {
|
|
131
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
132
|
+
}
|
|
133
|
+
function checkSelector(value, at, push, required, index = false) {
|
|
134
|
+
if (value === void 0 && !required) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (typeof value !== "string") {
|
|
138
|
+
push("missing", at);
|
|
139
|
+
} else if (!(index && value === "#") && parseSelector(value) === null) {
|
|
140
|
+
push("selector", at);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function checkTemplate(value, at, push) {
|
|
144
|
+
if (typeof value !== "string") {
|
|
145
|
+
push("missing", at);
|
|
146
|
+
} else if (templateNames(value) === null) {
|
|
147
|
+
push("template", at);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function checkQuery(query, at, push) {
|
|
151
|
+
if (query === void 0) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (!isObject(query)) {
|
|
155
|
+
push("missing", `${at}.query`);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
for (const [k, v] of Object.entries(query)) {
|
|
159
|
+
checkTemplate(v, `${at}.query.${k}`, push);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function isBatch(batch) {
|
|
163
|
+
return isObject(batch) && Number.isInteger(batch.max) && batch.max >= 1 && typeof batch.join === "string";
|
|
164
|
+
}
|
|
165
|
+
function checkRequest(r, at, entities, push) {
|
|
166
|
+
if (!isObject(r)) {
|
|
167
|
+
push("missing", at);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (r.method !== void 0 && r.method !== "GET" && r.method !== "POST") {
|
|
171
|
+
push("missing", `${at}.method`);
|
|
172
|
+
}
|
|
173
|
+
checkTemplate(r.path, `${at}.path`, push);
|
|
174
|
+
if (typeof r.path === "string" && !r.path.startsWith("/")) {
|
|
175
|
+
push("template", `${at}.path`);
|
|
176
|
+
}
|
|
177
|
+
checkQuery(r.query, at, push);
|
|
178
|
+
checkSelector(r.records, `${at}.records`, push, true);
|
|
179
|
+
if (typeof r.entity !== "string") {
|
|
180
|
+
push("missing", `${at}.entity`);
|
|
181
|
+
} else if (!entities.has(r.entity)) {
|
|
182
|
+
push("unknown-entity", `${at}.entity`);
|
|
183
|
+
}
|
|
184
|
+
if (r.batch !== void 0 && !isBatch(r.batch)) {
|
|
185
|
+
push("batch", `${at}.batch`);
|
|
186
|
+
}
|
|
187
|
+
if (r.paging !== void 0) {
|
|
188
|
+
checkPaging(r.paging, `${at}.paging`, push);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function checkPaging(p, at, push) {
|
|
192
|
+
const paging = p;
|
|
193
|
+
if (!isObject(paging)) {
|
|
194
|
+
push("paging", at);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
switch (paging.style) {
|
|
198
|
+
case "cursor":
|
|
199
|
+
if (typeof paging.param !== "string" || typeof paging.first !== "string") {
|
|
200
|
+
push("paging", at);
|
|
201
|
+
}
|
|
202
|
+
checkSelector(paging.next, `${at}.next`, push, true);
|
|
203
|
+
break;
|
|
204
|
+
case "offset": {
|
|
205
|
+
const size = paging.size;
|
|
206
|
+
const ok = typeof paging.param === "string" && isObject(size) && typeof size.param === "string" && Number.isInteger(size.value) && size.value > 0 && (paging.unit === void 0 || paging.unit === "items" || paging.unit === "pages") && (paging.base === void 0 || paging.base === 0 || paging.base === 1);
|
|
207
|
+
if (!ok) {
|
|
208
|
+
push("paging", at);
|
|
209
|
+
}
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
case "link-header":
|
|
213
|
+
if (paging.rel !== void 0 && typeof paging.rel !== "string") {
|
|
214
|
+
push("paging", at);
|
|
215
|
+
}
|
|
216
|
+
break;
|
|
217
|
+
case "next-url":
|
|
218
|
+
checkSelector(paging.next, `${at}.next`, push, true);
|
|
219
|
+
break;
|
|
220
|
+
default:
|
|
221
|
+
push("paging", `${at}.style`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function checkEdgeRule(rule, at, entities, push) {
|
|
225
|
+
if (!isObject(rule)) {
|
|
226
|
+
push("missing", at);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const r = rule;
|
|
230
|
+
if (typeof r.type !== "string") {
|
|
231
|
+
push("missing", `${at}.type`);
|
|
232
|
+
}
|
|
233
|
+
checkSelector(r.each, `${at}.each`, push, false);
|
|
234
|
+
if ("pairs" in r) {
|
|
235
|
+
checkSelector(r.pairs, `${at}.pairs`, push, true);
|
|
236
|
+
} else {
|
|
237
|
+
checkSelector(r.to, `${at}.to`, push, true);
|
|
238
|
+
checkSelector(r.from, `${at}.from`, push, false);
|
|
239
|
+
if (isObject(r.fields)) {
|
|
240
|
+
for (const [k, v] of Object.entries(r.fields)) {
|
|
241
|
+
checkSelector(v, `${at}.fields.${k}`, push, true);
|
|
242
|
+
}
|
|
243
|
+
} else if (r.fields !== void 0) {
|
|
244
|
+
push("missing", `${at}.fields`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (r.entity !== void 0 && (typeof r.entity !== "string" || !entities.has(r.entity))) {
|
|
248
|
+
push("unknown-entity", `${at}.entity`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function checkEntity(e, at, entities, push) {
|
|
252
|
+
if (!isObject(e)) {
|
|
253
|
+
push("missing", at);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
checkSelector(e.id, `${at}.id`, push, true, true);
|
|
257
|
+
if (e.stripPrefix !== void 0 && typeof e.stripPrefix !== "string") {
|
|
258
|
+
push("missing", `${at}.stripPrefix`);
|
|
259
|
+
}
|
|
260
|
+
if (e.label !== void 0 && typeof e.label !== "string") {
|
|
261
|
+
push("missing", `${at}.label`);
|
|
262
|
+
}
|
|
263
|
+
if (e.node !== void 0 && e.node) {
|
|
264
|
+
push("missing", `${at}.node`);
|
|
265
|
+
}
|
|
266
|
+
if (isObject(e.fields)) {
|
|
267
|
+
for (const [k, v] of Object.entries(e.fields)) {
|
|
268
|
+
checkSelector(v, `${at}.fields.${k}`, push, true, true);
|
|
269
|
+
}
|
|
270
|
+
} else if (e.fields !== void 0) {
|
|
271
|
+
push("missing", `${at}.fields`);
|
|
272
|
+
}
|
|
273
|
+
if (Array.isArray(e.edges)) {
|
|
274
|
+
e.edges.forEach((rule, i) => {
|
|
275
|
+
checkEdgeRule(rule, `${at}.edges.${String(i)}`, entities, push);
|
|
276
|
+
});
|
|
277
|
+
} else if (e.edges !== void 0) {
|
|
278
|
+
push("missing", `${at}.edges`);
|
|
279
|
+
}
|
|
280
|
+
if (Array.isArray(e.embedded)) {
|
|
281
|
+
e.embedded.forEach((em, i) => {
|
|
282
|
+
const where = `${at}.embedded.${String(i)}`;
|
|
283
|
+
if (!isObject(em)) {
|
|
284
|
+
push("missing", where);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
checkSelector(em.at, `${where}.at`, push, true);
|
|
288
|
+
if (typeof em.entity !== "string" || !entities.has(em.entity)) {
|
|
289
|
+
push("unknown-entity", `${where}.entity`);
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
} else if (e.embedded !== void 0) {
|
|
293
|
+
push("missing", `${at}.embedded`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
function checkRequestNames(m, requests, push) {
|
|
297
|
+
const names = [
|
|
298
|
+
["load", m.load],
|
|
299
|
+
["hydrate", m.hydrate],
|
|
300
|
+
["seed", m.seed]
|
|
301
|
+
];
|
|
302
|
+
if (isObject(m.expand)) {
|
|
303
|
+
names.push(["expand.in", m.expand.in], ["expand.out", m.expand.out]);
|
|
304
|
+
} else {
|
|
305
|
+
names.push(["expand", m.expand]);
|
|
306
|
+
}
|
|
307
|
+
for (const [at, name] of names) {
|
|
308
|
+
if (name === void 0 && at !== "load") {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (typeof name !== "string") {
|
|
312
|
+
push("missing", at);
|
|
313
|
+
} else if (!requests.has(name)) {
|
|
314
|
+
push("unknown-request", at);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
function checkEndpoint(endpoint, push) {
|
|
319
|
+
let url = null;
|
|
320
|
+
try {
|
|
321
|
+
url = new URL(typeof endpoint === "string" ? endpoint : "");
|
|
322
|
+
} catch {
|
|
323
|
+
}
|
|
324
|
+
if (url === null || url.protocol !== "https:" && url.protocol !== "http:" || url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "") {
|
|
325
|
+
push("endpoint", "endpoint");
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
function checkRestMapping(mapping) {
|
|
329
|
+
const issues = [];
|
|
330
|
+
const push = (code, at) => {
|
|
331
|
+
issues.push(Object.freeze({ code, at }));
|
|
332
|
+
};
|
|
333
|
+
if (!isObject(mapping)) {
|
|
334
|
+
push("missing", "");
|
|
335
|
+
return issues;
|
|
336
|
+
}
|
|
337
|
+
const m = mapping;
|
|
338
|
+
if (m.version !== 1) {
|
|
339
|
+
push("version", "version");
|
|
340
|
+
}
|
|
341
|
+
checkEndpoint(m.endpoint, push);
|
|
342
|
+
const requests = isObject(m.requests) ? m.requests : {};
|
|
343
|
+
const entities = isObject(m.entities) ? m.entities : {};
|
|
344
|
+
if (!isObject(m.requests)) {
|
|
345
|
+
push("missing", "requests");
|
|
346
|
+
}
|
|
347
|
+
if (!isObject(m.entities)) {
|
|
348
|
+
push("missing", "entities");
|
|
349
|
+
}
|
|
350
|
+
const entityNames = new Set(Object.keys(entities));
|
|
351
|
+
for (const [name, r] of Object.entries(requests)) {
|
|
352
|
+
checkRequest(r, `requests.${name}`, entityNames, push);
|
|
353
|
+
}
|
|
354
|
+
for (const [name, e] of Object.entries(entities)) {
|
|
355
|
+
checkEntity(e, `entities.${name}`, entityNames, push);
|
|
356
|
+
}
|
|
357
|
+
checkRequestNames(m, new Set(Object.keys(requests)), push);
|
|
358
|
+
checkLimits(m, push);
|
|
359
|
+
checkSelector(m.modified, "modified", push, false);
|
|
360
|
+
if (m.directed !== void 0 && typeof m.directed !== "boolean") {
|
|
361
|
+
push("missing", "directed");
|
|
362
|
+
}
|
|
363
|
+
return issues;
|
|
364
|
+
}
|
|
365
|
+
function checkLimits(m, push) {
|
|
366
|
+
for (const [at, value] of [
|
|
367
|
+
["rateLimit.requests", m.rateLimit?.requests],
|
|
368
|
+
["rateLimit.perMs", m.rateLimit?.perMs]
|
|
369
|
+
]) {
|
|
370
|
+
if (m.rateLimit !== void 0 && !(typeof value === "number" && value > 0)) {
|
|
371
|
+
push("number", at);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (m.budgetHeaders !== void 0 && (typeof m.budgetHeaders.remaining !== "string" || m.budgetHeaders.reset !== void 0 && typeof m.budgetHeaders.reset !== "string")) {
|
|
375
|
+
push("missing", "budgetHeaders");
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
function firstPosition(paging) {
|
|
379
|
+
switch (paging?.style) {
|
|
380
|
+
case "cursor":
|
|
381
|
+
return paging.first;
|
|
382
|
+
case "offset":
|
|
383
|
+
return paging.base ?? 0;
|
|
384
|
+
default:
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
function pageUrl(url, paging, position, endpoint, report) {
|
|
389
|
+
if (position === null) {
|
|
390
|
+
return url;
|
|
391
|
+
}
|
|
392
|
+
const out = new URL(url);
|
|
393
|
+
switch (paging?.style) {
|
|
394
|
+
case "cursor":
|
|
395
|
+
out.searchParams.set(paging.param, String(position));
|
|
396
|
+
return out;
|
|
397
|
+
case "offset":
|
|
398
|
+
out.searchParams.set(paging.param, String(position));
|
|
399
|
+
out.searchParams.set(paging.size.param, String(paging.size.value));
|
|
400
|
+
return out;
|
|
401
|
+
default:
|
|
402
|
+
return checkOrigin(new URL(String(position), url), endpoint, report);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
function firstPageUrl(url, paging, endpoint, report) {
|
|
406
|
+
return pageUrl(url, paging, firstPosition(paging), endpoint, report);
|
|
407
|
+
}
|
|
408
|
+
function linkOf(header, rel) {
|
|
409
|
+
for (const part of header.split(/,(?=\s*<)/)) {
|
|
410
|
+
const m = /^\s*<([^>]*)>(.*)$/.exec(part);
|
|
411
|
+
if (m === null) {
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
const rels = /;\s*rel="?([^";]+)"?/i.exec(m[2]);
|
|
415
|
+
if (rels?.[1].split(/\s+/).includes(rel)) {
|
|
416
|
+
return m[1];
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
function nextLink(rel, page, endpoint, report) {
|
|
422
|
+
const header = page.headers.get("link");
|
|
423
|
+
if (header === null) {
|
|
424
|
+
if (page.runtime === "browser") {
|
|
425
|
+
failOn(report, "E_SOURCE_RESPONSE", "the Link header cannot be read", {
|
|
426
|
+
expected: "link-header",
|
|
427
|
+
contentType: page.headers.get("content-type")
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
432
|
+
const next = linkOf(header, rel);
|
|
433
|
+
return next === null ? null : checkOrigin(new URL(next, page.url), endpoint, report).href;
|
|
434
|
+
}
|
|
435
|
+
function nextPosition(paging, position, page, endpoint, report) {
|
|
436
|
+
switch (paging?.style) {
|
|
437
|
+
case "cursor": {
|
|
438
|
+
const next = selectOne(page.body, paging.next);
|
|
439
|
+
return typeof next === "string" && next !== "" || typeof next === "number" ? next : null;
|
|
440
|
+
}
|
|
441
|
+
case "offset": {
|
|
442
|
+
if (page.records < paging.size.value || page.records === 0) {
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
const step = paging.unit === "pages" ? 1 : paging.size.value;
|
|
446
|
+
return Number(position) + step;
|
|
447
|
+
}
|
|
448
|
+
case "link-header":
|
|
449
|
+
return nextLink(paging.rel ?? "next", page, endpoint, report);
|
|
450
|
+
case "next-url": {
|
|
451
|
+
const next = selectOne(page.body, paging.next);
|
|
452
|
+
return typeof next === "string" && next !== "" ? checkOrigin(new URL(next, page.url), endpoint, report).href : null;
|
|
453
|
+
}
|
|
454
|
+
default:
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
function newState(known = []) {
|
|
459
|
+
return { full: /* @__PURE__ */ new Set(), stubs: /* @__PURE__ */ new Set(), known: new Set(known), modified: null };
|
|
460
|
+
}
|
|
461
|
+
function idText(value, entity) {
|
|
462
|
+
if (typeof value !== "string" && typeof value !== "number") {
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
const text = String(value);
|
|
466
|
+
const prefix = entity?.stripPrefix;
|
|
467
|
+
return prefix !== void 0 && prefix !== "" && text.startsWith(prefix) ? text.slice(prefix.length) : text;
|
|
468
|
+
}
|
|
469
|
+
function fieldValue(record, selector, index) {
|
|
470
|
+
if (selector === "#") {
|
|
471
|
+
return index;
|
|
472
|
+
}
|
|
473
|
+
return selector.includes("[]") ? select(record, selector) : selectOne(record, selector);
|
|
474
|
+
}
|
|
475
|
+
class PageWriter {
|
|
476
|
+
/**
|
|
477
|
+
* Create one.
|
|
478
|
+
* @param mapping - the mapping
|
|
479
|
+
* @param state - the load's state
|
|
480
|
+
*/
|
|
481
|
+
constructor(mapping, state) {
|
|
482
|
+
this.mapping = mapping;
|
|
483
|
+
this.state = state;
|
|
484
|
+
this.out = { nodes: [], edges: [] };
|
|
485
|
+
this.pending = [];
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Add the records of an entity, and their embedded records.
|
|
489
|
+
* @param records - the records
|
|
490
|
+
* @param entityName - their entity
|
|
491
|
+
*/
|
|
492
|
+
addRecords(records, entityName) {
|
|
493
|
+
const entity = this.mapping.entities[entityName];
|
|
494
|
+
records.forEach((record, index) => {
|
|
495
|
+
const id = entity.node === false ? null : idText(fieldValue(record, entity.id, index), entity);
|
|
496
|
+
if (entity.node !== false) {
|
|
497
|
+
if (id === null) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
this.addNode(record, index, id, entityName, entity);
|
|
501
|
+
}
|
|
502
|
+
const modified = this.mapping.modified === void 0 ? void 0 : selectOne(record, this.mapping.modified);
|
|
503
|
+
if (typeof modified === "string" && (this.state.modified === null || modified > this.state.modified)) {
|
|
504
|
+
this.state.modified = modified;
|
|
505
|
+
}
|
|
506
|
+
this.pending.push({ record, entity: entityName, id });
|
|
507
|
+
for (const em of entity.embedded ?? []) {
|
|
508
|
+
this.addRecords(select(record, em.at), em.entity);
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Write a full record.
|
|
514
|
+
* @param record - the record
|
|
515
|
+
* @param index - its position
|
|
516
|
+
* @param id - its id
|
|
517
|
+
* @param entityName - its entity
|
|
518
|
+
* @param entity - the entity
|
|
519
|
+
*/
|
|
520
|
+
addNode(record, index, id, entityName, entity) {
|
|
521
|
+
const attrs = { labels: [entity.label ?? entityName] };
|
|
522
|
+
if (entity.fields === void 0) {
|
|
523
|
+
for (const [k, v] of Object.entries(record)) {
|
|
524
|
+
if (k !== "id" && k !== "labels" && (typeof v === "string" || typeof v === "number" || typeof v === "boolean")) {
|
|
525
|
+
attrs[k] = v;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
} else {
|
|
529
|
+
for (const [name, selector] of Object.entries(entity.fields)) {
|
|
530
|
+
const v = fieldValue(record, selector, index);
|
|
531
|
+
if (v !== void 0) {
|
|
532
|
+
attrs[name] = v;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
if (this.state.stubs.has(id)) {
|
|
537
|
+
attrs[SOURCE_STUB_ATTR] = false;
|
|
538
|
+
}
|
|
539
|
+
this.state.full.add(id);
|
|
540
|
+
this.out.nodes.push({ id, ...attrs });
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Make sure an edge end exists: a stub when no record of it was written and the caller does not
|
|
544
|
+
* hold it.
|
|
545
|
+
* @param id - the id
|
|
546
|
+
* @param entity - its entity, when known
|
|
547
|
+
*/
|
|
548
|
+
end(id, entity) {
|
|
549
|
+
const { full, stubs, known } = this.state;
|
|
550
|
+
if (full.has(id) || stubs.has(id) || known.has(id)) {
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
stubs.add(id);
|
|
554
|
+
this.out.nodes.push({
|
|
555
|
+
id,
|
|
556
|
+
[SOURCE_STUB_ATTR]: true,
|
|
557
|
+
...entity === void 0 ? {} : { [SOURCE_ENTITY_ATTR]: entity }
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Run one edge rule over a record.
|
|
562
|
+
* @param rule - the rule
|
|
563
|
+
* @param record - the record
|
|
564
|
+
* @param entityName - the record's entity
|
|
565
|
+
* @param recordId - the record's id (null for a container)
|
|
566
|
+
*/
|
|
567
|
+
runRule(rule, record, entityName, recordId) {
|
|
568
|
+
const scopes = rule.each === void 0 ? [record] : select(record, rule.each);
|
|
569
|
+
if ("pairs" in rule) {
|
|
570
|
+
this.runPairsRule(rule, scopes, entityName);
|
|
571
|
+
} else {
|
|
572
|
+
this.runLinkRule(rule, scopes, entityName, recordId);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Run a pairs rule: an edge between every two distinct ids in each scope.
|
|
577
|
+
* @param rule - the rule
|
|
578
|
+
* @param scopes - the scopes it runs over
|
|
579
|
+
* @param entityName - the record's entity
|
|
580
|
+
*/
|
|
581
|
+
runPairsRule(rule, scopes, entityName) {
|
|
582
|
+
const entityOf = rule.entity ?? entityName;
|
|
583
|
+
const entity = this.mapping.entities[entityOf];
|
|
584
|
+
for (const scope of scopes) {
|
|
585
|
+
const ids = [...new Set(select(scope, rule.pairs).map((v) => idText(v, entity)))].filter(
|
|
586
|
+
(v) => v !== null
|
|
587
|
+
);
|
|
588
|
+
for (let i = 0; i < ids.length; i++) {
|
|
589
|
+
for (let j = i + 1; j < ids.length; j++) {
|
|
590
|
+
this.end(ids[i], entityOf);
|
|
591
|
+
this.end(ids[j], entityOf);
|
|
592
|
+
this.out.edges.push({ source: ids[i], target: ids[j], type: rule.type });
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Run a from/to rule: an edge from the record (or a selected id) to each selected id.
|
|
599
|
+
* @param rule - the rule
|
|
600
|
+
* @param scopes - the scopes it runs over
|
|
601
|
+
* @param entityName - the record's entity
|
|
602
|
+
* @param recordId - the record's id (null for a container)
|
|
603
|
+
*/
|
|
604
|
+
runLinkRule(rule, scopes, entityName, recordId) {
|
|
605
|
+
const own = this.mapping.entities[entityName];
|
|
606
|
+
const targetEntity = rule.entity === void 0 ? own : this.mapping.entities[rule.entity];
|
|
607
|
+
for (const scope of scopes) {
|
|
608
|
+
const from = rule.from === void 0 ? recordId : idText(selectOne(scope, rule.from), own);
|
|
609
|
+
if (from === null) {
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
const tos = select(scope, rule.to).map((t) => idText(t, targetEntity)).filter((v) => v !== null);
|
|
613
|
+
for (const to of tos) {
|
|
614
|
+
this.end(from, rule.from === void 0 ? entityName : void 0);
|
|
615
|
+
this.end(to, rule.entity);
|
|
616
|
+
this.out.edges.push({ ...edgeFields(rule.fields, scope), source: from, target: to, type: rule.type });
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Run the edge rules of every record added.
|
|
622
|
+
* @returns the page
|
|
623
|
+
*/
|
|
624
|
+
finish() {
|
|
625
|
+
for (const { record, entity, id } of this.pending) {
|
|
626
|
+
for (const rule of this.mapping.entities[entity].edges ?? []) {
|
|
627
|
+
this.runRule(rule, record, entity, id);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
this.pending.length = 0;
|
|
631
|
+
return this.out;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
function edgeFields(fields, scope) {
|
|
635
|
+
const out = {};
|
|
636
|
+
for (const [name, selector] of Object.entries(fields ?? {})) {
|
|
637
|
+
const v = fieldValue(scope, selector, 0);
|
|
638
|
+
if (v !== void 0) {
|
|
639
|
+
out[name] = v;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
return out;
|
|
643
|
+
}
|
|
644
|
+
function toRecords(mapping, groups, state) {
|
|
645
|
+
const writer = new PageWriter(mapping, state);
|
|
646
|
+
for (const g of groups) {
|
|
647
|
+
writer.addRecords(g.records, g.entity);
|
|
648
|
+
}
|
|
649
|
+
return writer.finish();
|
|
650
|
+
}
|
|
651
|
+
const AUTH_CODES = /* @__PURE__ */ new Set(["E_SOURCE_AUTH", "E_SOURCE_FORBIDDEN"]);
|
|
652
|
+
function resetDelayMs(reset) {
|
|
653
|
+
return Math.max(0, reset > 1e9 ? reset * 1e3 - Date.now() : reset * 1e3);
|
|
654
|
+
}
|
|
655
|
+
class RestRun {
|
|
656
|
+
/**
|
|
657
|
+
* Create one.
|
|
658
|
+
* @param plan - the mapping and values
|
|
659
|
+
* @param ctx - the context
|
|
660
|
+
* @param paced - whether this run paces itself (the generic source, whose descriptor cannot)
|
|
661
|
+
*/
|
|
662
|
+
constructor(plan2, ctx, paced) {
|
|
663
|
+
this.plan = plan2;
|
|
664
|
+
this.ctx = ctx;
|
|
665
|
+
this.paced = paced;
|
|
666
|
+
this.facts = {};
|
|
667
|
+
this.last = 0;
|
|
668
|
+
this.endpoint = new URL(plan2.mapping.endpoint);
|
|
669
|
+
if (ctx.endpoint !== null && originOf(ctx.endpoint) !== this.endpoint.origin) {
|
|
670
|
+
failOn(ctx.report, "E_SOURCE_PARAM", "the endpoint is not the mapping's", {
|
|
671
|
+
name: "endpoint",
|
|
672
|
+
reason: "origin"
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
/** Wait out the mapping's own rate limit (the generic source only). */
|
|
677
|
+
async pace() {
|
|
678
|
+
const rate = this.plan.mapping.rateLimit;
|
|
679
|
+
if (!this.paced || rate === void 0) {
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
const wait = this.last + rate.perMs / rate.requests - Date.now();
|
|
683
|
+
if (wait > 0) {
|
|
684
|
+
await sleep(wait, this.ctx.signal);
|
|
685
|
+
}
|
|
686
|
+
this.last = Date.now();
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Record the budget headers of a response.
|
|
690
|
+
* @param headers - the response headers
|
|
691
|
+
*/
|
|
692
|
+
noteBudget(headers) {
|
|
693
|
+
const names = this.plan.mapping.budgetHeaders;
|
|
694
|
+
const remaining = names === void 0 ? null : headers.get(names.remaining);
|
|
695
|
+
if (names === void 0 || remaining === null || !Number.isFinite(Number(remaining))) {
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
const reset = names.reset === void 0 ? null : Number(headers.get(names.reset) ?? Number.NaN);
|
|
699
|
+
const resetMs = reset === null || !Number.isFinite(reset) ? void 0 : resetDelayMs(reset);
|
|
700
|
+
this.facts.budget = { remaining: Number(remaining), ...resetMs === void 0 ? {} : { resetMs } };
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* Read one page of a request.
|
|
704
|
+
* @param name - the request name
|
|
705
|
+
* @param values - the template values
|
|
706
|
+
* @param position - the page's position, or undefined for the first page
|
|
707
|
+
* @param headers - extra request headers (validation)
|
|
708
|
+
* @returns the page
|
|
709
|
+
*/
|
|
710
|
+
async read(name, values, position, headers) {
|
|
711
|
+
const request = this.plan.mapping.requests[name];
|
|
712
|
+
const { report } = this.ctx;
|
|
713
|
+
const built = buildRequest(this.endpoint, request, values, report);
|
|
714
|
+
const url = position === void 0 ? firstPageUrl(built.url, request.paging, this.endpoint, report) : pageUrl(built.url, request.paging, position, this.endpoint, report);
|
|
715
|
+
await this.pace();
|
|
716
|
+
const response = await this.ctx.fetch(url, {
|
|
717
|
+
...built.init,
|
|
718
|
+
headers: { accept: "application/json", ...built.init.headers, ...headers },
|
|
719
|
+
allowStatus: [304]
|
|
720
|
+
});
|
|
721
|
+
this.noteBudget(response.headers);
|
|
722
|
+
if (response.status === 304) {
|
|
723
|
+
return { records: [], next: null, headers: response.headers, status: 304 };
|
|
724
|
+
}
|
|
725
|
+
const text = await response.text();
|
|
726
|
+
let body;
|
|
727
|
+
try {
|
|
728
|
+
body = JSON.parse(text);
|
|
729
|
+
} catch {
|
|
730
|
+
failOn(report, "E_SOURCE_RESPONSE", "the response is not JSON", {
|
|
731
|
+
expected: "json",
|
|
732
|
+
contentType: response.headers.get("content-type")
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
const records = selectRecords(body, request.records);
|
|
736
|
+
const here = position ?? null;
|
|
737
|
+
const next = nextPosition(
|
|
738
|
+
request.paging,
|
|
739
|
+
position ?? (request.paging?.style === "offset" ? request.paging.base ?? 0 : here),
|
|
740
|
+
{ body, headers: response.headers, url, records: records.length, runtime: this.ctx.runtime },
|
|
741
|
+
this.endpoint,
|
|
742
|
+
report
|
|
743
|
+
);
|
|
744
|
+
return { records, next, headers: response.headers, status: response.status };
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Record what the facts say so far, so the report carries them even when a later page fails.
|
|
748
|
+
* @param state - the load's record state
|
|
749
|
+
* @param next - where to resume, for an expansion
|
|
750
|
+
* @returns the report so far
|
|
751
|
+
*/
|
|
752
|
+
finish(state, next = null) {
|
|
753
|
+
if (state?.modified !== null && state?.modified !== void 0) {
|
|
754
|
+
this.facts.validators = { ...this.facts.validators, modified: state.modified };
|
|
755
|
+
}
|
|
756
|
+
return this.ctx.finish({ ...this.facts, next });
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* Note the HTTP validators of a load's first response.
|
|
760
|
+
* @param headers - its headers
|
|
761
|
+
*/
|
|
762
|
+
noteValidators(headers) {
|
|
763
|
+
const etag = headers.get("etag");
|
|
764
|
+
const lastModified = headers.get("last-modified");
|
|
765
|
+
this.facts.validators = {
|
|
766
|
+
...this.facts.validators,
|
|
767
|
+
...etag === null ? {} : { etag },
|
|
768
|
+
...lastModified === null ? {} : { lastModified }
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* The graph facts of a first page.
|
|
773
|
+
* @returns the meta
|
|
774
|
+
*/
|
|
775
|
+
meta() {
|
|
776
|
+
const { directed } = this.plan.mapping;
|
|
777
|
+
return directed === void 0 ? void 0 : { directed };
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
function stringValues(params, skip) {
|
|
781
|
+
const out = {};
|
|
782
|
+
for (const [k, v] of Object.entries(params)) {
|
|
783
|
+
if (k !== skip && (typeof v === "string" || typeof v === "number" || typeof v === "boolean")) {
|
|
784
|
+
out[k] = String(v);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
return out;
|
|
788
|
+
}
|
|
789
|
+
async function* loadPages(run) {
|
|
790
|
+
const { mapping, values } = run.plan;
|
|
791
|
+
const { cursor } = run.ctx;
|
|
792
|
+
if (cursor !== null && cursor.r !== mapping.load) {
|
|
793
|
+
failOn(run.ctx.report, "E_SOURCE_PARAM", "the cursor is not this mapping's", {
|
|
794
|
+
name: "cursor",
|
|
795
|
+
reason: "stale-cursor"
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
const state = newState();
|
|
799
|
+
const groups = [];
|
|
800
|
+
if (cursor === null && mapping.seed !== void 0) {
|
|
801
|
+
const seed = await run.read(mapping.seed, values, void 0);
|
|
802
|
+
groups.push({ records: seed.records, entity: mapping.requests[mapping.seed].entity });
|
|
803
|
+
}
|
|
804
|
+
const { entity } = mapping.requests[mapping.load];
|
|
805
|
+
let position = cursor === null ? void 0 : cursor.at;
|
|
806
|
+
let first = true;
|
|
807
|
+
for (; ; ) {
|
|
808
|
+
const page = await run.read(mapping.load, values, position);
|
|
809
|
+
if (first && cursor === null) {
|
|
810
|
+
run.noteValidators(page.headers);
|
|
811
|
+
}
|
|
812
|
+
const out = toRecords(mapping, [...groups.splice(0), { records: page.records, entity }], state);
|
|
813
|
+
run.finish(state);
|
|
814
|
+
const next = page.next === null ? null : { r: mapping.load, at: page.next };
|
|
815
|
+
yield { nodes: out.nodes, edges: out.edges, next, meta: first ? run.meta() : void 0 };
|
|
816
|
+
if (page.next === null) {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
first = false;
|
|
820
|
+
position = page.next;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
function writePage(out, sink, ctx, types) {
|
|
824
|
+
const { report } = ctx;
|
|
825
|
+
let n = 0;
|
|
826
|
+
for (const { id, ...attrs } of out.nodes) {
|
|
827
|
+
if (n++ % 64 === 0) {
|
|
828
|
+
throwIfAborted(ctx.signal);
|
|
829
|
+
}
|
|
830
|
+
try {
|
|
831
|
+
sink.addNodeRecord(id, attrs);
|
|
832
|
+
report.counts.nodes++;
|
|
833
|
+
} catch (err) {
|
|
834
|
+
report.recordError(err, { element: String(id) });
|
|
835
|
+
report.counts.skippedNodes++;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
for (const { source, target, ...attrs } of out.edges) {
|
|
839
|
+
if (n++ % 64 === 0) {
|
|
840
|
+
throwIfAborted(ctx.signal);
|
|
841
|
+
}
|
|
842
|
+
if (types !== void 0 && !types.has(String(attrs.type))) {
|
|
843
|
+
continue;
|
|
844
|
+
}
|
|
845
|
+
try {
|
|
846
|
+
sink.addEdgeRecord(source, target, attrs);
|
|
847
|
+
report.counts.edges++;
|
|
848
|
+
} catch (err) {
|
|
849
|
+
report.recordError(err, { element: `${String(source)} -> ${String(target)}` });
|
|
850
|
+
report.counts.skippedEdges++;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
function expandRequests(mapping, request) {
|
|
855
|
+
if (request.depth === 0) {
|
|
856
|
+
return mapping.hydrate === void 0 ? [] : [mapping.hydrate];
|
|
857
|
+
}
|
|
858
|
+
const { expand } = mapping;
|
|
859
|
+
if (typeof expand === "string" || expand === void 0) {
|
|
860
|
+
return expand === void 0 ? [] : [expand];
|
|
861
|
+
}
|
|
862
|
+
const direction = request.direction ?? "both";
|
|
863
|
+
const names = [direction !== "out" ? expand.in : void 0, direction !== "in" ? expand.out : void 0];
|
|
864
|
+
return [...new Set(names.filter((n) => n !== void 0))];
|
|
865
|
+
}
|
|
866
|
+
function batches(ids, max) {
|
|
867
|
+
const out = [];
|
|
868
|
+
for (let i = 0; i < ids.length; i += max) {
|
|
869
|
+
out.push(ids.slice(i, i + max));
|
|
870
|
+
}
|
|
871
|
+
return out;
|
|
872
|
+
}
|
|
873
|
+
async function expandInto(run, request, sink) {
|
|
874
|
+
return new Expansion(run, request, sink).expand();
|
|
875
|
+
}
|
|
876
|
+
class Expansion {
|
|
877
|
+
/**
|
|
878
|
+
* Check the expansion and set the sink's direction.
|
|
879
|
+
* @param run - the call
|
|
880
|
+
* @param request - the seeds and how far to go
|
|
881
|
+
* @param sink - where to write
|
|
882
|
+
*/
|
|
883
|
+
constructor(run, request, sink) {
|
|
884
|
+
this.run = run;
|
|
885
|
+
this.request = request;
|
|
886
|
+
this.sink = sink;
|
|
887
|
+
this.added = 0;
|
|
888
|
+
this.wrote = false;
|
|
889
|
+
const { ctx } = run;
|
|
890
|
+
this.mapping = run.plan.mapping;
|
|
891
|
+
this.names = expandRequests(this.mapping, request);
|
|
892
|
+
if (this.names.length === 0) {
|
|
893
|
+
failOn(ctx.report, "E_SOURCE_UNSUPPORTED", "the mapping has no request for this expansion", {
|
|
894
|
+
feature: request.depth === 0 ? "hydrate" : "expand"
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
if (request.ids.length === 0) {
|
|
898
|
+
failOn(ctx.report, "E_SOURCE_PARAM", "an expansion needs seed ids", { name: "ids", reason: "required" });
|
|
899
|
+
}
|
|
900
|
+
this.state = newState([...request.ids.map(String), ...(request.exclude ?? []).map(String)]);
|
|
901
|
+
this.types = request.relationshipTypes === void 0 ? void 0 : new Set(request.relationshipTypes);
|
|
902
|
+
if (this.mapping.directed !== void 0 && sink.edgeCount === 0) {
|
|
903
|
+
sink.setDirected(this.mapping.directed);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Run every hop.
|
|
908
|
+
* @returns the report
|
|
909
|
+
*/
|
|
910
|
+
async expand() {
|
|
911
|
+
let frontier = this.request.ids.map(String);
|
|
912
|
+
const depth = Math.max(1, this.request.depth ?? 1);
|
|
913
|
+
for (let hop = 1; hop <= depth && frontier.length > 0; hop++) {
|
|
914
|
+
const reached = [];
|
|
915
|
+
const stop = await this.hop(hop, frontier, reached);
|
|
916
|
+
if (stop !== null) {
|
|
917
|
+
return stop;
|
|
918
|
+
}
|
|
919
|
+
frontier = [...new Set(reached)];
|
|
920
|
+
}
|
|
921
|
+
return this.run.finish(this.state, null);
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* Run one hop: every request over every batch of the frontier.
|
|
925
|
+
* @param hop - the hop, from 1
|
|
926
|
+
* @param frontier - the ids this hop starts from
|
|
927
|
+
* @param reached - collects the ids this hop adds
|
|
928
|
+
* @returns the report when the expansion stopped, else null
|
|
929
|
+
*/
|
|
930
|
+
async hop(hop, frontier, reached) {
|
|
931
|
+
for (const [x, name] of this.names.entries()) {
|
|
932
|
+
const max = this.mapping.requests[name].batch?.max ?? 1;
|
|
933
|
+
for (const [b, batch] of batches(frontier, max).entries()) {
|
|
934
|
+
if (this.skipped({ hop, x, b })) {
|
|
935
|
+
continue;
|
|
936
|
+
}
|
|
937
|
+
const stop = await this.readBatch({ hop, x, b }, name, batch, frontier, reached);
|
|
938
|
+
if (stop !== null) {
|
|
939
|
+
return stop;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
return null;
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Whether a resumed first hop already read this batch.
|
|
947
|
+
* @param at - the batch
|
|
948
|
+
* @returns true to skip it
|
|
949
|
+
*/
|
|
950
|
+
skipped(at) {
|
|
951
|
+
const { hop, x, b } = at;
|
|
952
|
+
const resume = this.run.ctx.cursor;
|
|
953
|
+
if (hop !== 1 || resume === null) {
|
|
954
|
+
return false;
|
|
955
|
+
}
|
|
956
|
+
const rx = Number(resume.x);
|
|
957
|
+
return x < rx || x === rx && b < Number(resume.b);
|
|
958
|
+
}
|
|
959
|
+
/**
|
|
960
|
+
* Where a batch starts: the recorded position for the batch a first hop stopped in.
|
|
961
|
+
* @param at - the batch
|
|
962
|
+
* @returns the position, or undefined for the first page
|
|
963
|
+
*/
|
|
964
|
+
startPosition(at) {
|
|
965
|
+
const { hop, x, b } = at;
|
|
966
|
+
const resume = this.run.ctx.cursor;
|
|
967
|
+
return hop === 1 && resume !== null && x === Number(resume.x) && b === Number(resume.b) ? resume.at ?? void 0 : void 0;
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* Read one batch page by page.
|
|
971
|
+
* @param at - the batch
|
|
972
|
+
* @param name - the request
|
|
973
|
+
* @param batch - its ids
|
|
974
|
+
* @param frontier - the hop's ids
|
|
975
|
+
* @param reached - collects the ids it adds
|
|
976
|
+
* @returns the report when the expansion stopped, else null
|
|
977
|
+
*/
|
|
978
|
+
async readBatch(at, name, batch, frontier, reached) {
|
|
979
|
+
const r = this.mapping.requests[name];
|
|
980
|
+
const own = { ...this.run.plan.values, id: batch[0], ids: batch.join(r.batch?.join ?? ",") };
|
|
981
|
+
let position = this.startPosition(at);
|
|
982
|
+
for (; ; ) {
|
|
983
|
+
let page;
|
|
984
|
+
try {
|
|
985
|
+
page = await this.run.read(name, own, position);
|
|
986
|
+
} catch (err) {
|
|
987
|
+
return this.authStop(err, at.hop === 1 ? { x: at.x, b: at.b, at: position ?? null } : null);
|
|
988
|
+
}
|
|
989
|
+
this.writeNew(page, r.entity, reached);
|
|
990
|
+
const stop = this.capStop(at, page, frontier);
|
|
991
|
+
if (stop !== null || page.next === null) {
|
|
992
|
+
return stop;
|
|
993
|
+
}
|
|
994
|
+
position = page.next;
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* Keep what was written when a later page needs a credential; rethrow anything else.
|
|
999
|
+
* @param err - what the page threw
|
|
1000
|
+
* @param cursor - where to resume
|
|
1001
|
+
* @returns the report
|
|
1002
|
+
*/
|
|
1003
|
+
authStop(err, cursor) {
|
|
1004
|
+
if (!this.wrote || !(err instanceof ImportError) || !AUTH_CODES.has(String(err.issue?.code))) {
|
|
1005
|
+
throw err;
|
|
1006
|
+
}
|
|
1007
|
+
const p = err.issue?.params ?? {};
|
|
1008
|
+
warnOn(this.run.ctx.report, "W_SOURCE_AUTH", "a later page needs a credential; the pages before it are kept", {
|
|
1009
|
+
origin: typeof p.origin === "string" ? p.origin : this.run.endpoint.origin,
|
|
1010
|
+
status: typeof p.status === "number" ? p.status : null
|
|
1011
|
+
});
|
|
1012
|
+
return this.run.finish(this.state, cursor);
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Write a page and collect the nodes it added.
|
|
1016
|
+
* @param page - the page
|
|
1017
|
+
* @param entity - its records' entity
|
|
1018
|
+
* @param reached - collects the ids it adds
|
|
1019
|
+
*/
|
|
1020
|
+
writeNew(page, entity, reached) {
|
|
1021
|
+
const { state } = this;
|
|
1022
|
+
const before = /* @__PURE__ */ new Set([...state.full, ...state.stubs]);
|
|
1023
|
+
const out = toRecords(this.mapping, [{ records: page.records, entity }], state);
|
|
1024
|
+
writePage(out, this.sink, this.run.ctx, this.types);
|
|
1025
|
+
this.wrote = true;
|
|
1026
|
+
for (const node of out.nodes) {
|
|
1027
|
+
const id = String(node.id);
|
|
1028
|
+
if (!before.has(id) && !state.known.has(id)) {
|
|
1029
|
+
reached.push(id);
|
|
1030
|
+
this.added++;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Stop at the expansion's limit or the load's caps.
|
|
1036
|
+
* @param at - the batch
|
|
1037
|
+
* @param page - the page just written
|
|
1038
|
+
* @param frontier - the hop's ids
|
|
1039
|
+
* @returns the report when a cap was reached, else null
|
|
1040
|
+
*/
|
|
1041
|
+
capStop(at, page, frontier) {
|
|
1042
|
+
const { hop, x, b } = at;
|
|
1043
|
+
const { ctx } = this.run;
|
|
1044
|
+
const limited = this.request.limit !== void 0 && this.added >= this.request.limit;
|
|
1045
|
+
if (limited) {
|
|
1046
|
+
warnOn(ctx.report, "W_SOURCE_LIMIT", "the expansion reached its limit", {
|
|
1047
|
+
limit: "limit",
|
|
1048
|
+
value: this.added
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
if (!limited && !ctx.limits.reached()) {
|
|
1052
|
+
return null;
|
|
1053
|
+
}
|
|
1054
|
+
const more = page.next === null ? null : { x, b, at: page.next };
|
|
1055
|
+
return this.run.finish(
|
|
1056
|
+
this.state,
|
|
1057
|
+
hop === 1 ? more ?? nextBatch(x, b, this.names, frontier, this.mapping) : null
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
function nextBatch(x, b, names, frontier, mapping) {
|
|
1062
|
+
const count = Math.ceil(frontier.length / (mapping.requests[names[x]].batch?.max ?? 1));
|
|
1063
|
+
if (b + 1 < count) {
|
|
1064
|
+
return { x, b: b + 1, at: null };
|
|
1065
|
+
}
|
|
1066
|
+
return x + 1 < names.length ? { x: x + 1, b: 0, at: null } : null;
|
|
1067
|
+
}
|
|
1068
|
+
async function validateRun(run, seen) {
|
|
1069
|
+
const { mapping, values } = run.plan;
|
|
1070
|
+
const headers = {};
|
|
1071
|
+
if (seen.etag !== void 0) {
|
|
1072
|
+
headers["if-none-match"] = seen.etag;
|
|
1073
|
+
}
|
|
1074
|
+
if (seen.lastModified !== void 0) {
|
|
1075
|
+
headers["if-modified-since"] = seen.lastModified;
|
|
1076
|
+
}
|
|
1077
|
+
const state = newState();
|
|
1078
|
+
const groups = [];
|
|
1079
|
+
if (mapping.seed !== void 0) {
|
|
1080
|
+
const seed = await run.read(mapping.seed, values, void 0);
|
|
1081
|
+
groups.push({ records: seed.records, entity: mapping.requests[mapping.seed].entity });
|
|
1082
|
+
}
|
|
1083
|
+
const page = await run.read(mapping.load, values, void 0, headers);
|
|
1084
|
+
if (page.status === 304) {
|
|
1085
|
+
return { status: "current", via: seen.etag === void 0 ? "modified" : "etag", validators: seen };
|
|
1086
|
+
}
|
|
1087
|
+
toRecords(mapping, [...groups, { records: page.records, entity: mapping.requests[mapping.load].entity }], state);
|
|
1088
|
+
run.noteValidators(page.headers);
|
|
1089
|
+
const now = {
|
|
1090
|
+
...run.facts.validators,
|
|
1091
|
+
...state.modified === null ? {} : { modified: state.modified }
|
|
1092
|
+
};
|
|
1093
|
+
if (seen.etag !== void 0 && now.etag !== void 0) {
|
|
1094
|
+
return { status: seen.etag === now.etag ? "current" : "changed", via: "etag", validators: now };
|
|
1095
|
+
}
|
|
1096
|
+
if (seen.modified !== void 0 && now.modified !== void 0) {
|
|
1097
|
+
return now.modified > seen.modified ? { status: "changed", via: "modified", changedAt: now.modified, validators: now } : { status: "current", via: "modified", validators: now };
|
|
1098
|
+
}
|
|
1099
|
+
return { status: "unverifiable", validators: now };
|
|
1100
|
+
}
|
|
1101
|
+
function restMethods(plan2, paced) {
|
|
1102
|
+
return {
|
|
1103
|
+
records: (params, ctx) => loadPages(new RestRun(plan2(params, ctx, "load"), ctx, paced)),
|
|
1104
|
+
expand: (request, sink, ctx) => expandInto(new RestRun(plan2(request.params, ctx, "expand"), ctx, paced), request, sink),
|
|
1105
|
+
async probe(params, ctx) {
|
|
1106
|
+
const run = new RestRun(plan2(params, ctx, "probe"), ctx, paced);
|
|
1107
|
+
const page = await run.read(run.plan.mapping.load, run.plan.values, void 0);
|
|
1108
|
+
if (page.records.length === 0 && page.status !== 304) {
|
|
1109
|
+
failOn(ctx.report, "E_SOURCE_NOT_FOUND", "the load request found no records", {
|
|
1110
|
+
what: "records",
|
|
1111
|
+
value: run.plan.mapping.load
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
return { ok: true };
|
|
1115
|
+
},
|
|
1116
|
+
validate: (params, seen, ctx) => validateRun(new RestRun(plan2(params, ctx, "validate"), ctx, paced), seen)
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1119
|
+
function checkedMapping(mapping, ctx) {
|
|
1120
|
+
const [issue] = checkRestMapping(mapping);
|
|
1121
|
+
if (issue !== void 0) {
|
|
1122
|
+
failOn(ctx.report, "E_SOURCE_PARAM", `the mapping is invalid at ${issue.at}`, {
|
|
1123
|
+
name: "mapping",
|
|
1124
|
+
reason: issue.code,
|
|
1125
|
+
at: issue.at
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
return mapping;
|
|
1129
|
+
}
|
|
1130
|
+
function restSource(mapping, info) {
|
|
1131
|
+
const [issue] = checkRestMapping(mapping);
|
|
1132
|
+
if (issue !== void 0) {
|
|
1133
|
+
failAlone("E_SOURCE_INVALID", `the mapping of ${info.id} is invalid at ${issue.at}`, {
|
|
1134
|
+
id: info.id,
|
|
1135
|
+
reason: "mapping",
|
|
1136
|
+
at: issue.at
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
const { id, ...fields } = info;
|
|
1140
|
+
const auth = mapping.auth === void 0 ? [] : [mapping.auth.kind];
|
|
1141
|
+
const descriptor = Object.freeze({
|
|
1142
|
+
plainName: id,
|
|
1143
|
+
kind: "rest",
|
|
1144
|
+
params: mapping.params ?? [],
|
|
1145
|
+
defaultEndpoint: mapping.endpoint,
|
|
1146
|
+
auth,
|
|
1147
|
+
authRequired: auth.length === 0 ? "none" : "optional",
|
|
1148
|
+
...mapping.rateLimit === void 0 ? {} : { rateLimit: mapping.rateLimit },
|
|
1149
|
+
...fields
|
|
1150
|
+
});
|
|
1151
|
+
return defineSource({
|
|
1152
|
+
id,
|
|
1153
|
+
descriptor,
|
|
1154
|
+
...restMethods((params) => ({ mapping, values: stringValues(params) }), false)
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
const restMappingSource = defineSource({
|
|
1158
|
+
id: REST_SOURCE_ID,
|
|
1159
|
+
descriptor: REST_DESCRIPTOR,
|
|
1160
|
+
...restMethods(
|
|
1161
|
+
(params, ctx) => ({ mapping: checkedMapping(params.mapping, ctx), values: stringValues(params, "mapping") }),
|
|
1162
|
+
true
|
|
1163
|
+
)
|
|
1164
|
+
});
|
|
1165
|
+
const PREFIX = "https://openalex.org/";
|
|
1166
|
+
const WORK_FIELDS = "id,display_name,publication_year,cited_by_count,updated_date,referenced_works";
|
|
1167
|
+
function works(filter, perPage, paged) {
|
|
1168
|
+
return {
|
|
1169
|
+
path: "/works",
|
|
1170
|
+
query: { filter, "per-page": perPage, select: "{select}" },
|
|
1171
|
+
batch: { max: 50, join: "|" },
|
|
1172
|
+
records: "results",
|
|
1173
|
+
entity: "work",
|
|
1174
|
+
...paged ? { paging: { style: "cursor", param: "cursor", first: "*", next: "meta.next_cursor" } } : {}
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
const named = { id: "id", stripPrefix: PREFIX, fields: { name: "display_name" } };
|
|
1178
|
+
const OPENALEX_MAPPING = Object.freeze({
|
|
1179
|
+
version: 1,
|
|
1180
|
+
endpoint: "https://api.openalex.org",
|
|
1181
|
+
load: "citing",
|
|
1182
|
+
seed: "by-id",
|
|
1183
|
+
expand: { in: "citing", out: "by-id" },
|
|
1184
|
+
hydrate: "by-id",
|
|
1185
|
+
directed: true,
|
|
1186
|
+
modified: "updated_date",
|
|
1187
|
+
auth: { kind: "api-key", query: "api_key" },
|
|
1188
|
+
rateLimit: { requests: 10, perMs: 1e3 },
|
|
1189
|
+
budgetHeaders: { remaining: "x-ratelimit-remaining", reset: "x-ratelimit-reset" },
|
|
1190
|
+
requests: {
|
|
1191
|
+
citing: works("cites:{ids}", "200", true),
|
|
1192
|
+
"by-id": works("openalex:{ids}", "50", false),
|
|
1193
|
+
authored: works("authorships.author.id:{ids}", "200", true),
|
|
1194
|
+
"authors-by-id": {
|
|
1195
|
+
path: "/authors",
|
|
1196
|
+
query: { filter: "openalex:{ids}", "per-page": "50", select: "id,display_name" },
|
|
1197
|
+
batch: { max: 50, join: "|" },
|
|
1198
|
+
records: "results",
|
|
1199
|
+
entity: "author"
|
|
1200
|
+
}
|
|
1201
|
+
},
|
|
1202
|
+
entities: {
|
|
1203
|
+
work: {
|
|
1204
|
+
id: "id",
|
|
1205
|
+
stripPrefix: PREFIX,
|
|
1206
|
+
fields: {
|
|
1207
|
+
title: "display_name",
|
|
1208
|
+
year: "publication_year",
|
|
1209
|
+
citedBy: "cited_by_count",
|
|
1210
|
+
updated: "updated_date"
|
|
1211
|
+
},
|
|
1212
|
+
edges: [
|
|
1213
|
+
{ to: "referenced_works[]", type: "cites", entity: "work" },
|
|
1214
|
+
{ to: "authorships[].author.id", type: "authored_by", entity: "author" },
|
|
1215
|
+
{
|
|
1216
|
+
each: "authorships[]",
|
|
1217
|
+
from: "author.id",
|
|
1218
|
+
to: "institutions[].id",
|
|
1219
|
+
type: "affiliated_with",
|
|
1220
|
+
entity: "institution"
|
|
1221
|
+
},
|
|
1222
|
+
{ to: "topics[].id", type: "has_topic", entity: "topic" }
|
|
1223
|
+
],
|
|
1224
|
+
embedded: [
|
|
1225
|
+
{ at: "authorships[].author", entity: "author" },
|
|
1226
|
+
{ at: "authorships[].institutions[]", entity: "institution" },
|
|
1227
|
+
{ at: "topics[]", entity: "topic" }
|
|
1228
|
+
]
|
|
1229
|
+
},
|
|
1230
|
+
author: named,
|
|
1231
|
+
institution: named,
|
|
1232
|
+
topic: named
|
|
1233
|
+
}
|
|
1234
|
+
});
|
|
1235
|
+
function includes(include) {
|
|
1236
|
+
const list = typeof include === "string" ? include.split(",") : [];
|
|
1237
|
+
if (Array.isArray(include)) {
|
|
1238
|
+
list.push(...include);
|
|
1239
|
+
}
|
|
1240
|
+
const out = new Set(list.map((v) => String(v).trim()).filter((v) => v !== ""));
|
|
1241
|
+
if (out.has("institutions")) {
|
|
1242
|
+
out.add("authors");
|
|
1243
|
+
}
|
|
1244
|
+
return out;
|
|
1245
|
+
}
|
|
1246
|
+
function citationMapping(include) {
|
|
1247
|
+
const { work } = OPENALEX_MAPPING.entities;
|
|
1248
|
+
const keepEdge = (type) => type === "cites" || type === "authored_by" && include.has("authors") || type === "affiliated_with" && include.has("institutions") || type === "has_topic" && include.has("topics");
|
|
1249
|
+
const keepEmbedded = (entity) => include.has(`${entity}s`);
|
|
1250
|
+
return {
|
|
1251
|
+
...OPENALEX_MAPPING,
|
|
1252
|
+
entities: {
|
|
1253
|
+
...OPENALEX_MAPPING.entities,
|
|
1254
|
+
work: {
|
|
1255
|
+
...work,
|
|
1256
|
+
edges: work.edges?.filter((e) => keepEdge(e.type)),
|
|
1257
|
+
embedded: work.embedded?.filter((e) => keepEmbedded(e.entity))
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
function coauthorshipMapping(include, seedIsWork) {
|
|
1263
|
+
const institutions = include.has("institutions");
|
|
1264
|
+
return {
|
|
1265
|
+
...OPENALEX_MAPPING,
|
|
1266
|
+
load: seedIsWork ? "by-id" : "authored",
|
|
1267
|
+
seed: void 0,
|
|
1268
|
+
expand: "authored",
|
|
1269
|
+
hydrate: "authors-by-id",
|
|
1270
|
+
directed: false,
|
|
1271
|
+
entities: {
|
|
1272
|
+
...OPENALEX_MAPPING.entities,
|
|
1273
|
+
work: {
|
|
1274
|
+
id: "id",
|
|
1275
|
+
// a rule's `from` is read with the record's own prefix
|
|
1276
|
+
stripPrefix: PREFIX,
|
|
1277
|
+
node: false,
|
|
1278
|
+
edges: [
|
|
1279
|
+
{ pairs: "authorships[].author.id", type: "coauthor", entity: "author" },
|
|
1280
|
+
...institutions ? [
|
|
1281
|
+
{
|
|
1282
|
+
each: "authorships[]",
|
|
1283
|
+
from: "author.id",
|
|
1284
|
+
to: "institutions[].id",
|
|
1285
|
+
type: "affiliated_with",
|
|
1286
|
+
entity: "institution"
|
|
1287
|
+
}
|
|
1288
|
+
] : []
|
|
1289
|
+
],
|
|
1290
|
+
embedded: [
|
|
1291
|
+
{ at: "authorships[].author", entity: "author" },
|
|
1292
|
+
...institutions ? [{ at: "authorships[].institutions[]", entity: "institution" }] : []
|
|
1293
|
+
]
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
1298
|
+
function openalexId(value, name, letter, ctx) {
|
|
1299
|
+
const text = typeof value === "string" ? value.trim().replace(PREFIX, "") : "";
|
|
1300
|
+
if (!new RegExp(String.raw`^${letter}\d+$`, "i").test(text)) {
|
|
1301
|
+
failOn(ctx.report, "E_SOURCE_PARAM", `${name} is not an OpenAlex id`, { name, reason: "format" });
|
|
1302
|
+
}
|
|
1303
|
+
return text.toUpperCase();
|
|
1304
|
+
}
|
|
1305
|
+
function plan(params, ctx, purpose) {
|
|
1306
|
+
const graph = params.graph ?? "citation";
|
|
1307
|
+
const include = includes(params.include);
|
|
1308
|
+
const hasWork = params.work !== void 0 && params.work !== "";
|
|
1309
|
+
const hasAuthor = params.author !== void 0 && params.author !== "";
|
|
1310
|
+
if (purpose !== "expand" && hasWork === hasAuthor) {
|
|
1311
|
+
failOn(ctx.report, "E_SOURCE_PARAM", "give exactly one of work and author", {
|
|
1312
|
+
name: "work",
|
|
1313
|
+
reason: hasWork ? "exclusive" : "required"
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
let seed = "";
|
|
1317
|
+
if (hasWork) {
|
|
1318
|
+
seed = openalexId(params.work, "work", "W", ctx);
|
|
1319
|
+
} else if (hasAuthor) {
|
|
1320
|
+
seed = openalexId(params.author, "author", "A", ctx);
|
|
1321
|
+
}
|
|
1322
|
+
if (graph === "coauthorship") {
|
|
1323
|
+
return {
|
|
1324
|
+
mapping: coauthorshipMapping(include, hasWork),
|
|
1325
|
+
values: { ids: seed, select: purpose === "validate" ? "id,updated_date" : "id,updated_date,authorships" }
|
|
1326
|
+
};
|
|
1327
|
+
}
|
|
1328
|
+
let select2 = WORK_FIELDS + (include.has("authors") ? ",authorships" : "") + (include.has("topics") ? ",topics" : "");
|
|
1329
|
+
if (purpose === "validate") {
|
|
1330
|
+
select2 = "id,updated_date";
|
|
1331
|
+
}
|
|
1332
|
+
const mapping = citationMapping(include);
|
|
1333
|
+
return {
|
|
1334
|
+
mapping: hasWork ? mapping : { ...mapping, load: "authored", seed: void 0 },
|
|
1335
|
+
values: { ids: seed, select: select2 }
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
const ANY_ID = /^[WAIT]\d+$/;
|
|
1339
|
+
const methods = restMethods(plan, false);
|
|
1340
|
+
const openalexSource = defineSource({
|
|
1341
|
+
id: OPENALEX_SOURCE_ID,
|
|
1342
|
+
descriptor: OPENALEX_DESCRIPTOR,
|
|
1343
|
+
...methods,
|
|
1344
|
+
expand(request, sink, ctx) {
|
|
1345
|
+
for (const id of request.ids) {
|
|
1346
|
+
if (!ANY_ID.test(String(id))) {
|
|
1347
|
+
failOn(ctx.report, "E_SOURCE_PARAM", "an expansion seed is not an OpenAlex id", {
|
|
1348
|
+
name: "ids",
|
|
1349
|
+
reason: "format"
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
return methods.expand(request, sink, ctx);
|
|
1354
|
+
}
|
|
1355
|
+
});
|
|
1356
|
+
export {
|
|
1357
|
+
D as DEPS_DEV_MAPPING,
|
|
1358
|
+
OPENALEX_DESCRIPTOR,
|
|
1359
|
+
OPENALEX_MAPPING,
|
|
1360
|
+
REST_DESCRIPTOR,
|
|
1361
|
+
S as STRING_MAPPING,
|
|
1362
|
+
checkRestMapping,
|
|
1363
|
+
openalexSource,
|
|
1364
|
+
restMappingSource,
|
|
1365
|
+
restSource
|
|
1366
|
+
};
|
|
1367
|
+
//# sourceMappingURL=sources-rest.js.map
|