cocoda-sdk 3.3.4 → 3.4.1

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/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Cocoda SDK
2
- ![Node.js CI](https://github.com/gbv/cocoda-sdk/workflows/Node.js%20CI/badge.svg)
2
+ [![Test and build](https://github.com/gbv/cocoda-sdk/actions/workflows/test-and-build.yml/badge.svg)](https://github.com/gbv/cocoda-sdk/actions/workflows/test-and-build.yml)
3
3
  [![GitHub package version](https://img.shields.io/github/package-json/v/gbv/cocoda-sdk.svg?label=version)](https://github.com/gbv/cocoda-sdk)
4
4
  [![NPM package name](https://img.shields.io/badge/npm-cocoda--sdk-blue.svg)](https://www.npmjs.com/package/cocoda-sdk)
5
5
  [![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg)](https://github.com/RichardLitt/standard-readme)
@@ -167,6 +167,8 @@ The following providers are also exported, but have to be added via `cdk.addProv
167
167
  - **This integration is currently experimental and only supports LCSH and LCNAF.**
168
168
  - `Skohub` - access to concept schemes and concepts via a [SkoHub Vocabs](https://blog.lobid.org/2019/09/27/presenting-skohub-vocabs.html)
169
169
  - **This integration is currently experimental. Only vocabularies that use a [slash namespace pattern]([hash](https://www.w3.org/2001/sw/BestPractices/VM/http-examples/2006-01-18/#slash)) with dereferenceable URIs are supported.**
170
+ - `LobidApi` - access to GND via [lobid](https://lobid.org)
171
+ - **This integration is currently experimental.**
170
172
  - `MyCoRe` - access to vocabularies via [MyCoRe](https://www.mycore.de/)
171
173
  - **This integration is currently experimental. Only one vocabulary per registry is supported. Not recommended for large vocabularies as all of the vocabulary data is loaded and kept in memory.**
172
174
  - `ReconciliationApi` - access to mapping suggestions via a [OpenRefine Reconciliation API](https://github.com/OpenRefine/OpenRefine/wiki/Reconciliation-Service-API)
@@ -33,6 +33,7 @@ __export(src_exports, {
33
33
  CocodaSDK: () => CocodaSDK,
34
34
  ConceptApiProvider: () => ConceptApiProvider,
35
35
  LabelSearchSuggestionProvider: () => LabelSearchSuggestionProvider,
36
+ LobidApiProvider: () => LobidApiProvider,
36
37
  LocApiProvider: () => LocApiProvider,
37
38
  LocalMappingsProvider: () => LocalMappingsProvider,
38
39
  MappingsApiProvider: () => MappingsApiProvider,
@@ -120,7 +121,7 @@ var InvalidProviderError = class extends CDKError {
120
121
  };
121
122
 
122
123
  // src/lib/CocodaSDK.js
123
- var import_axios3 = __toESM(require("axios"), 1);
124
+ var import_axios4 = __toESM(require("axios"), 1);
124
125
 
125
126
  // src/utils/lodash.js
126
127
  var import_get = __toESM(require("lodash/get.js"), 1);
@@ -140,7 +141,7 @@ var import_omit = __toESM(require("lodash/omit.js"), 1);
140
141
  var import_concat = __toESM(require("lodash/concat.js"), 1);
141
142
 
142
143
  // src/lib/CocodaSDK.js
143
- var import_jskos_tools12 = __toESM(require("jskos-tools"), 1);
144
+ var import_jskos_tools13 = __toESM(require("jskos-tools"), 1);
144
145
 
145
146
  // src/providers/index.js
146
147
  var providers_exports = {};
@@ -148,6 +149,7 @@ __export(providers_exports, {
148
149
  BaseProvider: () => BaseProvider,
149
150
  ConceptApiProvider: () => ConceptApiProvider,
150
151
  LabelSearchSuggestionProvider: () => LabelSearchSuggestionProvider,
152
+ LobidApiProvider: () => LobidApiProvider,
151
153
  LocApiProvider: () => LocApiProvider,
152
154
  LocalMappingsProvider: () => LocalMappingsProvider,
153
155
  MappingsApiProvider: () => MappingsApiProvider,
@@ -1122,7 +1124,7 @@ var LocalMappingsProvider = class extends BaseProvider {
1122
1124
  throw new InvalidOrMissingParameterError({ parameter: "mapping", message: "Duplicate URI" });
1123
1125
  }
1124
1126
  if (!mapping.created) {
1125
- mapping.created = new Date().toISOString();
1127
+ mapping.created = (/* @__PURE__ */ new Date()).toISOString();
1126
1128
  }
1127
1129
  if (!mapping.modified) {
1128
1130
  mapping.modified = mapping.created;
@@ -1158,7 +1160,7 @@ var LocalMappingsProvider = class extends BaseProvider {
1158
1160
  if (!mapping.created) {
1159
1161
  mapping.created = localMappings[index].created;
1160
1162
  }
1161
- mapping.modified = new Date().toISOString();
1163
+ mapping.modified = (/* @__PURE__ */ new Date()).toISOString();
1162
1164
  localMappings[index] = mapping;
1163
1165
  localMappings = localMappings.map((mapping2) => import_jskos_tools2.default.minifyMapping(mapping2));
1164
1166
  try {
@@ -1190,7 +1192,7 @@ var LocalMappingsProvider = class extends BaseProvider {
1190
1192
  if (!mapping.created) {
1191
1193
  mapping.created = localMappings[index].created;
1192
1194
  }
1193
- mapping.modified = new Date().toISOString();
1195
+ mapping.modified = (/* @__PURE__ */ new Date()).toISOString();
1194
1196
  localMappings[index] = Object.assign(localMappings[index], mapping);
1195
1197
  localMappings = localMappings.map((mapping2) => import_jskos_tools2.default.minifyMapping(mapping2));
1196
1198
  try {
@@ -2273,11 +2275,15 @@ var ConceptApiProvider = class extends BaseProvider {
2273
2275
  if (schemeUri) {
2274
2276
  import_set.default(config, "params.uri", schemeUri);
2275
2277
  }
2276
- return this.axios({
2278
+ let types = await this.axios({
2277
2279
  ...config,
2278
2280
  method: "get",
2279
2281
  url: this._api.types
2280
2282
  });
2283
+ if (schemeUri) {
2284
+ types = types.filter((type) => !type.inScheme || import_jskos_tools5.default.isContainedIn(scheme, type.inScheme));
2285
+ }
2286
+ return types;
2281
2287
  }
2282
2288
  };
2283
2289
  ConceptApiProvider.providerName = "ConceptApi";
@@ -3536,8 +3542,243 @@ var SkohubProvider = class extends BaseProvider {
3536
3542
  SkohubProvider.providerName = "Skohub";
3537
3543
  SkohubProvider.providerType = "http://bartoc.org/api-type/skohub";
3538
3544
 
3539
- // src/providers/mycore-provider.js
3545
+ // src/providers/lobid-api-provider.js
3540
3546
  var import_jskos_tools11 = __toESM(require("jskos-tools"), 1);
3547
+ var import_axios3 = __toESM(require("axios"), 1);
3548
+ var gndJson = {
3549
+ uri: "http://bartoc.org/en/node/430",
3550
+ concepts: [
3551
+ null
3552
+ ],
3553
+ topConcepts: [],
3554
+ type: [
3555
+ "http://www.w3.org/2004/02/skos/core#ConceptScheme"
3556
+ ],
3557
+ DISPLAY: {
3558
+ hideNotation: true
3559
+ },
3560
+ identifier: [
3561
+ "http://www.wikidata.org/entity/Q36578"
3562
+ ],
3563
+ license: [
3564
+ {
3565
+ uri: "http://creativecommons.org/publicdomain/zero/1.0/"
3566
+ }
3567
+ ],
3568
+ namespace: "https://d-nb.info/gnd/",
3569
+ notation: [
3570
+ "GND"
3571
+ ],
3572
+ notationPattern: "[0-9X-]+",
3573
+ prefLabel: {
3574
+ de: "Gemeinsame Normdatei",
3575
+ en: "Integrated Authority File"
3576
+ },
3577
+ types: [
3578
+ {
3579
+ uri: "https://d-nb.info/standards/elementset/gnd#DifferentiatedPerson",
3580
+ prefLabel: {
3581
+ de: "Person",
3582
+ en: "Person"
3583
+ }
3584
+ },
3585
+ {
3586
+ uri: "https://d-nb.info/standards/elementset/gnd#PlaceOrGeographicName",
3587
+ prefLabel: {
3588
+ de: "Geografikum",
3589
+ en: "Place"
3590
+ }
3591
+ },
3592
+ {
3593
+ uri: "https://d-nb.info/standards/elementset/gnd#CorporateBody",
3594
+ prefLabel: {
3595
+ de: "Organisation",
3596
+ en: "Organization"
3597
+ }
3598
+ },
3599
+ {
3600
+ uri: "https://d-nb.info/standards/elementset/gnd#SubjectHeading",
3601
+ prefLabel: {
3602
+ de: "Sachbegriff",
3603
+ en: "Subject"
3604
+ }
3605
+ },
3606
+ {
3607
+ uri: "https://d-nb.info/standards/elementset/gnd#Work",
3608
+ prefLabel: {
3609
+ de: "Werk",
3610
+ en: "Work"
3611
+ }
3612
+ },
3613
+ {
3614
+ uri: "https://d-nb.info/standards/elementset/gnd#ConferenceOrEvent",
3615
+ prefLabel: {
3616
+ de: "Konferenz oder Veranstaltung",
3617
+ en: "ConferenceOrEvent"
3618
+ }
3619
+ }
3620
+ ]
3621
+ };
3622
+ var gndTypeScheme = new import_jskos_tools11.default.ConceptScheme({
3623
+ uri: "https://d-nb.info/standards/elementset/gnd",
3624
+ namespace: "https://d-nb.info/standards/elementset/gnd#"
3625
+ });
3626
+ gndJson.types.forEach((type) => {
3627
+ type.notation = [gndTypeScheme.notationFromUri(type.uri)];
3628
+ });
3629
+ var gnd = new import_jskos_tools11.default.ConceptScheme(gndJson);
3630
+ var broaderProps = [
3631
+ "broaderTerm",
3632
+ "broaderTermGeneral",
3633
+ "broaderTermGeneric",
3634
+ "broaderTermInstantial",
3635
+ "broaderTermPartitive"
3636
+ ];
3637
+ function toJSKOS(data3) {
3638
+ const concept = {
3639
+ uri: data3.id,
3640
+ notation: [data3.gndIdentifier],
3641
+ prefLabel: { de: data3.preferredName },
3642
+ inScheme: [{ uri: gndJson.uri }]
3643
+ };
3644
+ if (data3.variantName) {
3645
+ concept.altLabel = { de: data3.variantName };
3646
+ }
3647
+ concept.type = data3.type.map((type) => gndTypeScheme.uriFromNotation(type)).filter(Boolean);
3648
+ concept.broader = [];
3649
+ broaderProps.forEach((prop) => {
3650
+ concept.broader = concept.broader.concat(data3[prop] || []);
3651
+ });
3652
+ concept.broader = concept.broader.map((broader) => ({ uri: broader.id }));
3653
+ concept.identifier = [concept.uri.replace("https://", "http://")];
3654
+ return concept;
3655
+ }
3656
+ function fixURI(uri) {
3657
+ if (uri && uri.startsWith("http://")) {
3658
+ return uri.replace("http://", "https://");
3659
+ }
3660
+ return uri;
3661
+ }
3662
+ var LobidApiProvider = class extends BaseProvider {
3663
+ _prepare() {
3664
+ this.has.schemes = true;
3665
+ this.has.data = true;
3666
+ this.has.concepts = true;
3667
+ this.has.narrower = true;
3668
+ this.has.suggest = true;
3669
+ this.has.search = true;
3670
+ this.has.types = true;
3671
+ listOfCapabilities.filter((c) => !this.has[c]).forEach((c) => {
3672
+ this.has[c] = false;
3673
+ });
3674
+ }
3675
+ /**
3676
+ * Used by `registryForScheme` (see src/lib/CocodaSDK.js) to determine a provider config for a concept schceme.
3677
+ *
3678
+ * @param {Object} options
3679
+ * @param {Object} options.url API URL for server
3680
+ * @returns {Object} provider configuration
3681
+ */
3682
+ static _registryConfigForBartocApiConfig({ url, scheme } = {}) {
3683
+ if (!url || !scheme || !import_jskos_tools11.default.compare(scheme, gndJson) || url !== "https://lobid.org/gnd/api") {
3684
+ return null;
3685
+ }
3686
+ return {
3687
+ api: "https://lobid.org/gnd/",
3688
+ schemes: [gndJson]
3689
+ };
3690
+ }
3691
+ async getSchemes() {
3692
+ return [gndJson];
3693
+ }
3694
+ async getTop() {
3695
+ return [];
3696
+ }
3697
+ async getConcepts({ concepts }) {
3698
+ if (!concepts) {
3699
+ throw new errors.InvalidOrMissingParameterError({ parameter: "concepts" });
3700
+ }
3701
+ if (!Array.isArray(concepts)) {
3702
+ concepts = [concepts];
3703
+ }
3704
+ const notations = concepts.map((concept) => {
3705
+ if (concept?.notation?.[0]) {
3706
+ return concept?.notation?.[0];
3707
+ }
3708
+ return gnd.notationFromUri(fixURI(concept?.uri));
3709
+ }).filter(Boolean);
3710
+ const errors = [];
3711
+ const results = await Promise.all(notations.map(async (notation) => {
3712
+ try {
3713
+ const result = await import_axios3.default.get(`${this._api.api}${notation}.json`);
3714
+ return toJSKOS(result.data);
3715
+ } catch (error) {
3716
+ errors.push(error);
3717
+ }
3718
+ }));
3719
+ if (errors.length === concepts.length) {
3720
+ throw errors[0];
3721
+ }
3722
+ return results.filter(Boolean);
3723
+ }
3724
+ async getNarrower({ concept, limit = 200, offset = 0 }) {
3725
+ if (!concept || !concept.uri) {
3726
+ throw new InvalidOrMissingParameterError({ parameter: "concept" });
3727
+ }
3728
+ const uri = fixURI(concept.uri);
3729
+ const q = broaderProps.map((prop) => `${prop}.id:"${uri}"`).join(" OR ");
3730
+ const result = await import_axios3.default.get(`${this._api.api}search`, {
3731
+ params: {
3732
+ q,
3733
+ format: "json",
3734
+ size: limit,
3735
+ from: offset
3736
+ }
3737
+ });
3738
+ return result.data.member.map((member) => toJSKOS(member));
3739
+ }
3740
+ async suggest(config) {
3741
+ const results = await this._search({ ...config, format: "json:suggest" });
3742
+ return [
3743
+ config.search,
3744
+ results.map((r) => r.label),
3745
+ [],
3746
+ results.map((r) => r.id)
3747
+ ];
3748
+ }
3749
+ async search(config) {
3750
+ const results = await this._search(config);
3751
+ return results.member.map((member) => toJSKOS(member));
3752
+ }
3753
+ async _search({ search, types, limit = 100, offset = 0, format = "json" }) {
3754
+ if (!search) {
3755
+ throw new InvalidOrMissingParameterError({ parameter: "search" });
3756
+ }
3757
+ let filter = "";
3758
+ types = types?.map((type) => gndTypeScheme.notationFromUri(fixURI(type))).filter(Boolean) || [];
3759
+ if (types.length) {
3760
+ filter = types.map((type) => `type:${type}`).join(" OR ");
3761
+ }
3762
+ const results = await import_axios3.default.get(`${this._api.api}search`, { params: {
3763
+ q: search,
3764
+ filter,
3765
+ format,
3766
+ size: limit,
3767
+ from: offset
3768
+ } });
3769
+ return results.data;
3770
+ }
3771
+ async getTypes({ scheme }) {
3772
+ if (!scheme || !import_jskos_tools11.default.compare(scheme, gndJson)) {
3773
+ throw new InvalidOrMissingParameterError({ parameter: "search", message: scheme?.uri ? `scheme ${scheme?.uri} not supported` : "" });
3774
+ }
3775
+ return gndJson.types;
3776
+ }
3777
+ };
3778
+ LobidApiProvider.providerName = "LobidApi";
3779
+
3780
+ // src/providers/mycore-provider.js
3781
+ var import_jskos_tools12 = __toESM(require("jskos-tools"), 1);
3541
3782
  var import_flexsearch2 = __toESM(require("flexsearch"), 1);
3542
3783
  var data2 = {};
3543
3784
  var MyCoReProvider = class extends BaseProvider {
@@ -3686,7 +3927,7 @@ var MyCoReProvider = class extends BaseProvider {
3686
3927
  if (!this._scheme) {
3687
3928
  await this.getSchemes(config);
3688
3929
  }
3689
- if (!import_jskos_tools11.default.compare(scheme, this._scheme)) {
3930
+ if (!import_jskos_tools12.default.compare(scheme, this._scheme)) {
3690
3931
  throw new InvalidOrMissingParameterError({ parameter: "scheme", message: "Requested vocabulary seems to be unsupported by this API." });
3691
3932
  }
3692
3933
  return data2[this._scheme.uri].topConcepts.map(this._removeNarrower);
@@ -3752,7 +3993,7 @@ var MyCoReProvider = class extends BaseProvider {
3752
3993
  if (!this._scheme) {
3753
3994
  await this.getSchemes();
3754
3995
  }
3755
- if (!import_jskos_tools11.default.compare(scheme, this._scheme)) {
3996
+ if (!import_jskos_tools12.default.compare(scheme, this._scheme)) {
3756
3997
  throw new InvalidOrMissingParameterError({ parameter: "scheme", message: "Requested vocabulary seems to be unsupported by this API." });
3757
3998
  }
3758
3999
  const result = await data2[this._scheme.uri].searchIndex.search(search);
@@ -3772,8 +4013,8 @@ var MyCoReProvider = class extends BaseProvider {
3772
4013
  const concepts = await this.search(config);
3773
4014
  const result = [config.search, [], [], []];
3774
4015
  for (let concept of concepts) {
3775
- const notation = import_jskos_tools11.default.notation(concept);
3776
- const label = import_jskos_tools11.default.prefLabel(concept);
4016
+ const notation = import_jskos_tools12.default.notation(concept);
4017
+ const label = import_jskos_tools12.default.prefLabel(concept);
3777
4018
  result[1].push((notation ? notation + " " : "") + label);
3778
4019
  result[2].push("");
3779
4020
  result[3].push(concept.uri);
@@ -3817,7 +4058,7 @@ var CocodaSDK = class {
3817
4058
  */
3818
4059
  constructor(config) {
3819
4060
  this.config = config;
3820
- this.axios = import_axios3.default.create();
4061
+ this.axios = import_axios4.default.create();
3821
4062
  }
3822
4063
  /**
3823
4064
  * Method to set the configuration.
@@ -4073,7 +4314,7 @@ var CocodaSDK = class {
4073
4314
  scheme._registry = registry;
4074
4315
  scheme.__DETAILSLOADED__ = 1;
4075
4316
  scheme.type = scheme.type || ["http://www.w3.org/2004/02/skos/core#ConceptScheme"];
4076
- let otherScheme = schemes.find((s) => import_jskos_tools12.default.compare(s, scheme)), prio, otherPrio, override = false;
4317
+ let otherScheme = schemes.find((s) => import_jskos_tools13.default.compare(s, scheme)), prio, otherPrio, override = false;
4077
4318
  if (otherScheme) {
4078
4319
  prio = this.config.registries.indexOf(registry);
4079
4320
  if (prio != -1) {
@@ -4095,19 +4336,19 @@ var CocodaSDK = class {
4095
4336
  }
4096
4337
  if (!otherScheme || override) {
4097
4338
  if (override) {
4098
- let otherSchemeIndex = schemes.findIndex((s) => import_jskos_tools12.default.compare(s, otherScheme));
4339
+ let otherSchemeIndex = schemes.findIndex((s) => import_jskos_tools13.default.compare(s, otherScheme));
4099
4340
  if (otherSchemeIndex != -1) {
4100
4341
  schemes.splice(otherSchemeIndex, 1);
4101
4342
  }
4102
- scheme = import_jskos_tools12.default.merge(scheme, import_omit.default(otherScheme, ["concepts", "topConcepts"]), { mergeUris: true, skipPaths: ["_registry"] });
4343
+ scheme = import_jskos_tools13.default.merge(scheme, import_omit.default(otherScheme, ["concepts", "topConcepts"]), { mergeUris: true, skipPaths: ["_registry"] });
4103
4344
  }
4104
4345
  scheme._registry = registry;
4105
4346
  schemes.push(scheme);
4106
4347
  } else {
4107
- const index = schemes.findIndex((s) => import_jskos_tools12.default.compare(s, scheme));
4348
+ const index = schemes.findIndex((s) => import_jskos_tools13.default.compare(s, scheme));
4108
4349
  if (index != -1) {
4109
4350
  const otherSchemeRegistry = schemes[index]._registry;
4110
- schemes[index] = import_jskos_tools12.default.merge(schemes[index], import_omit.default(scheme, ["concepts", "topConcepts"]), { mergeUris: true, skipPaths: ["_registry"] });
4351
+ schemes[index] = import_jskos_tools13.default.merge(schemes[index], import_omit.default(scheme, ["concepts", "topConcepts"]), { mergeUris: true, skipPaths: ["_registry"] });
4111
4352
  schemes[index]._registry = otherSchemeRegistry;
4112
4353
  }
4113
4354
  }
@@ -4129,7 +4370,7 @@ var CocodaSDK = class {
4129
4370
  scheme._registry = newRegistry;
4130
4371
  }
4131
4372
  });
4132
- return import_jskos_tools12.default.sortSchemes(schemes.filter(Boolean));
4373
+ return import_jskos_tools13.default.sortSchemes(schemes.filter(Boolean));
4133
4374
  }
4134
4375
  registryForScheme(scheme) {
4135
4376
  let registry = scheme._registry;
@@ -4140,30 +4381,34 @@ var CocodaSDK = class {
4140
4381
  const url = config.url;
4141
4382
  if (registryCache[url]) {
4142
4383
  const registry2 = registryCache[url];
4143
- if (Array.isArray(registry2._jskos.schemes) && !import_jskos_tools12.default.isContainedIn(scheme, registry2._jskos.schemes)) {
4384
+ if (Array.isArray(registry2._jskos.schemes) && !import_jskos_tools13.default.isContainedIn(scheme, registry2._jskos.schemes)) {
4144
4385
  registry2._jskos.schemes.push(scheme);
4145
4386
  }
4146
4387
  return registry2;
4147
4388
  } else {
4148
- const provider = Object.values(providers).find((p) => p.providerType === type);
4149
- if (!provider || !provider._registryConfigForBartocApiConfig) {
4150
- continue;
4151
- }
4152
- const providerName = provider.providerName;
4153
4389
  config.scheme = scheme;
4154
- config = providers[providerName]._registryConfigForBartocApiConfig(config);
4155
- if (!config) {
4156
- continue;
4157
- }
4158
- config.provider = providerName;
4159
- try {
4160
- registry = this.initializeRegistry(config);
4161
- if (registry) {
4162
- registryCache[url] = registry;
4163
- return registry;
4390
+ for (const provider of Object.values(providers)) {
4391
+ if (provider.providerType && provider.providerType !== type) {
4392
+ continue;
4393
+ }
4394
+ if (!provider._registryConfigForBartocApiConfig) {
4395
+ continue;
4396
+ }
4397
+ const providerName = provider.providerName;
4398
+ const registryConfig = providers[providerName]._registryConfigForBartocApiConfig(config);
4399
+ if (!registryConfig) {
4400
+ continue;
4401
+ }
4402
+ registryConfig.provider = providerName;
4403
+ try {
4404
+ registry = this.initializeRegistry(registryConfig);
4405
+ if (registry) {
4406
+ registryCache[url] = registry;
4407
+ return registry;
4408
+ }
4409
+ } catch (error) {
4410
+ continue;
4164
4411
  }
4165
- } catch (error) {
4166
- continue;
4167
4412
  }
4168
4413
  }
4169
4414
  }
@@ -4182,6 +4427,7 @@ function addAllProviders(_cdk) {
4182
4427
  CocodaSDK,
4183
4428
  ConceptApiProvider,
4184
4429
  LabelSearchSuggestionProvider,
4430
+ LobidApiProvider,
4185
4431
  LocApiProvider,
4186
4432
  LocalMappingsProvider,
4187
4433
  MappingsApiProvider,