cocoda-sdk 1.0.13 → 2.0.0

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.
Files changed (36) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +74 -28
  3. package/dist/cjs/index.cjs +2673 -0
  4. package/dist/cocoda-sdk.js +33 -17423
  5. package/dist/cocoda-sdk.js.LICENSES.txt +105 -86
  6. package/dist/cocoda-sdk.js.map +7 -0
  7. package/dist/esm/errors/index.js +46 -0
  8. package/dist/esm/index.js +9 -0
  9. package/dist/esm/lib/CocodaSDK.js +269 -0
  10. package/dist/esm/providers/base-provider.js +368 -0
  11. package/dist/esm/providers/concept-api-provider.js +278 -0
  12. package/dist/esm/providers/index.js +20 -0
  13. package/dist/esm/providers/label-search-suggestion-provider.js +101 -0
  14. package/dist/esm/providers/loc-api-provider.js +185 -0
  15. package/dist/esm/providers/local-mappings-provider.js +337 -0
  16. package/dist/esm/providers/mappings-api-provider.js +264 -0
  17. package/dist/esm/providers/occurrences-api-provider.js +163 -0
  18. package/dist/esm/providers/reconciliation-api-provider.js +140 -0
  19. package/dist/esm/providers/skosmos-api-provider.js +345 -0
  20. package/{utils → dist/esm/utils}/index.js +40 -53
  21. package/dist/esm/utils/lodash.js +34 -0
  22. package/package.json +16 -17
  23. package/errors/index.js +0 -119
  24. package/index.js +0 -5
  25. package/lib/CocodaSDK.js +0 -360
  26. package/providers/base-provider.js +0 -581
  27. package/providers/concept-api-provider.js +0 -377
  28. package/providers/index.js +0 -34
  29. package/providers/label-search-suggestion-provider.js +0 -219
  30. package/providers/loc-api-provider.js +0 -275
  31. package/providers/local-mappings-provider.js +0 -459
  32. package/providers/mappings-api-provider.js +0 -396
  33. package/providers/occurrences-api-provider.js +0 -234
  34. package/providers/reconciliation-api-provider.js +0 -211
  35. package/providers/skosmos-api-provider.js +0 -441
  36. package/utils/lodash.js +0 -21
@@ -1,396 +0,0 @@
1
- const BaseProvider = require("./base-provider")
2
- const jskos = require("jskos-tools")
3
- const _ = require("../utils/lodash")
4
- const errors = require("../errors")
5
- const utils = require("../utils")
6
-
7
- // TODO: Check capabilities (`this.has`) and authorization (`this.isAuthorizedFor`) before actions.
8
-
9
- /**
10
- * JSKOS Mappings API.
11
- *
12
- * This class provides access to concept mappings via JSKOS API in [JSKOS format](https://gbv.github.io/jskos/).
13
- * See [jskos-server](https://github.com/gbv/jskos-server) for a JSKOS API reference implementation
14
- *
15
- * To use it in a registry, specify `provider` as "MappingsApi" and provide the API base URL as `api`:
16
- * ```json
17
- * {
18
- * "uri": "http://coli-conc.gbv.de/registry/coli-conc-mappings",
19
- * "provider": "MappingsApi",
20
- * "api": "https://coli-conc.gbv.de/api/"
21
- * }
22
- * ```
23
- *
24
- * If the `/status` endpoint can be queried, the remaining API methods will be taken from that. As a fallback, the default endpoints will be appended to `api`.
25
- *
26
- * Alternatively, you can provide the endpoints separately: `status`, `mappings`, `concordances`, `annotations`
27
- *
28
- * Additionally, the following JSKOS properties can be provided: `prefLabel`, `notation`, `definition`
29
- *
30
- * @extends BaseProvider
31
- * @category Providers
32
- */
33
- class MappingsApiProvider extends BaseProvider {
34
-
35
- /**
36
- * @private
37
- */
38
- _prepare() {
39
- // Set status endpoint only
40
- if (this._api.api && this._api.status === undefined) {
41
- this._api.status = utils.concatUrl(this._api.api, "/status")
42
- }
43
- }
44
-
45
- /**
46
- * @private
47
- */
48
- _setup() {
49
- // Fill `this._api` if necessary
50
- if (this._api.api) {
51
- const endpoints = {
52
- mappings: "/mappings",
53
- concordances: "/concordances",
54
- annotations: "/annotations",
55
- }
56
- for (let key of Object.keys(endpoints)) {
57
- if (this._api[key] === undefined) {
58
- this._api[key] = utils.concatUrl(this._api.api, endpoints[key])
59
- }
60
- }
61
- }
62
- this.has.mappings = this._api.mappings ? {} : false
63
- if (this.has.mappings) {
64
- this.has.mappings.read = !!_.get(this._config, "mappings.read", true)
65
- this.has.mappings.create = !!_.get(this._config, "mappings.create")
66
- this.has.mappings.update = !!_.get(this._config, "mappings.update")
67
- this.has.mappings.delete = !!_.get(this._config, "mappings.delete")
68
- this.has.mappings.anonymous = !!_.get(this._config, "mappings.anonymous")
69
- }
70
- this.has.concordances = !!this._api.concordances
71
- this.has.annotations = this._api.annotations ? {} : false
72
- if (this.has.annotations) {
73
- this.has.annotations.read = !!_.get(this._config, "annotations.read")
74
- this.has.annotations.create = !!_.get(this._config, "annotations.create")
75
- this.has.annotations.update = !!_.get(this._config, "annotations.update")
76
- this.has.annotations.delete = !!_.get(this._config, "annotations.delete")
77
- }
78
- this.has.auth = _.get(this._config, "auth.key") != null
79
- this._defaultParams = {
80
- properties: "annotations",
81
- }
82
- }
83
-
84
- /**
85
- * Returns a single mapping.
86
- *
87
- * @param {Object} config
88
- * @param {Object} config.mapping JSKOS mapping
89
- * @returns {Object} JSKOS mapping object
90
- */
91
- async getMapping({ mapping, ...config }) {
92
- if (!mapping) {
93
- throw new errors.InvalidOrMissingParameterError({ parameter: "mapping" })
94
- }
95
- if (!mapping.uri || !mapping.uri.startsWith(this._api.mappings)) {
96
- throw new errors.InvalidOrMissingParameterError({ parameter: "mapping", message: "URI doesn't seem to be part of this registry." })
97
- }
98
- try {
99
- return await this.axios({
100
- ...config,
101
- url: mapping.uri,
102
- params: {
103
- ...this._defaultParams,
104
- ...(config.params || {}),
105
- },
106
- })
107
- } catch (error) {
108
- if (_.get(error, "response.status") == 404) {
109
- return null
110
- }
111
- throw error
112
- }
113
- }
114
-
115
- /**
116
- * Returns a list of mappings.
117
- *
118
- * @param {Object} config request config with parameters
119
- * @returns {Object[]} array of JSKOS mapping objects
120
- */
121
- async getMappings({ from, fromScheme, to, toScheme, creator, type, partOf, offset, limit, direction, mode, identifier, sort, order, ...config }) {
122
- let params = {}, url = this._api.mappings
123
- if (from) {
124
- params.from = _.isString(from) ? from : from.uri
125
- }
126
- if (fromScheme) {
127
- params.fromScheme = _.isString(fromScheme) ? fromScheme : fromScheme.uri
128
- }
129
- if (to) {
130
- params.to = _.isString(to) ? to : to.uri
131
- }
132
- if (toScheme) {
133
- params.toScheme = _.isString(toScheme) ? toScheme : toScheme.uri
134
- }
135
- if (creator) {
136
- params.creator = _.isString(creator) ? creator : jskos.prefLabel(creator)
137
- }
138
- if (type) {
139
- params.type = _.isString(type) ? type : type.uri
140
- }
141
- if (partOf) {
142
- params.partOf = _.isString(partOf) ? partOf : partOf.uri
143
- }
144
- if (offset) {
145
- params.offset = offset
146
- }
147
- if (limit) {
148
- params.limit = limit
149
- }
150
- if (direction) {
151
- params.direction = direction
152
- }
153
- if (mode) {
154
- params.mode = mode
155
- }
156
- if (identifier) {
157
- params.identifier = identifier
158
- }
159
- if (sort) {
160
- params.sort = sort
161
- }
162
- if (order) {
163
- params.order = order
164
- }
165
- return this.axios({
166
- ...config,
167
- method: "get",
168
- url,
169
- params: {
170
- ...this._defaultParams,
171
- ...(config.params || {}),
172
- ...params,
173
- },
174
- })
175
- }
176
-
177
- /**
178
- * Creates a mapping.
179
- *
180
- * @param {Object} config
181
- * @param {Object} config.mapping JSKOS mapping
182
- * @returns {Object} JSKOS mapping object
183
- */
184
- async postMapping({ mapping, ...config }) {
185
- if (!mapping) {
186
- throw new errors.InvalidOrMissingParameterError({ parameter: "mapping" })
187
- }
188
- mapping = jskos.minifyMapping(mapping)
189
- mapping = jskos.addMappingIdentifiers(mapping)
190
- return this.axios({
191
- ...config,
192
- method: "post",
193
- url: this._api.mappings,
194
- data: mapping,
195
- params: {
196
- ...this._defaultParams,
197
- ...(config.params || {}),
198
- },
199
- })
200
- }
201
-
202
- /**
203
- * Overwrites a mapping.
204
- *
205
- * @param {Object} config
206
- * @param {Object} config.mapping JSKOS mapping
207
- * @returns {Object} JSKOS mapping object
208
- */
209
- async putMapping({ mapping, ...config }) {
210
- if (!mapping) {
211
- throw new errors.InvalidOrMissingParameterError({ parameter: "mapping" })
212
- }
213
- mapping = jskos.minifyMapping(mapping)
214
- mapping = jskos.addMappingIdentifiers(mapping)
215
- const uri = mapping.uri
216
- if (!uri || !uri.startsWith(this._api.mappings)) {
217
- throw new errors.InvalidOrMissingParameterError({ parameter: "mapping", message: "URI doesn't seem to be part of this registry." })
218
- }
219
- return this.axios({
220
- ...config,
221
- method: "put",
222
- url: uri,
223
- data: mapping,
224
- params: {
225
- ...this._defaultParams,
226
- ...(config.params || {}),
227
- },
228
- })
229
- }
230
-
231
- /**
232
- * Patches a mapping.
233
- *
234
- * @param {Object} config
235
- * @param {Object} config.mapping JSKOS mapping (or part of mapping)
236
- * @returns {Object} JSKOS mapping object
237
- */
238
- async patchMapping({ mapping, ...config }) {
239
- if (!mapping) {
240
- throw new errors.InvalidOrMissingParameterError({ parameter: "mapping" })
241
- }
242
- mapping = jskos.minifyMapping(mapping)
243
- mapping = jskos.addMappingIdentifiers(mapping)
244
- const uri = mapping.uri
245
- if (!uri || !uri.startsWith(this._api.mappings)) {
246
- throw new errors.InvalidOrMissingParameterError({ parameter: "mapping", message: "URI doesn't seem to be part of this registry." })
247
- }
248
- return this.axios({
249
- ...config,
250
- method: "patch",
251
- url: uri,
252
- data: mapping,
253
- params: {
254
- ...this._defaultParams,
255
- ...(config.params || {}),
256
- },
257
- })
258
- }
259
-
260
- /**
261
- * Deletes a mapping.
262
- *
263
- * @param {Object} config
264
- * @param {Object} config.mapping JSKOS mapping
265
- * @returns {boolean} `true` if deletion was successful
266
- */
267
- async deleteMapping({ mapping, ...config }) {
268
- if (!mapping) {
269
- throw new errors.InvalidOrMissingParameterError({ parameter: "mapping" })
270
- }
271
- const uri = mapping.uri
272
- if (!uri || !uri.startsWith(this._api.mappings)) {
273
- throw new errors.InvalidOrMissingParameterError({ parameter: "mapping", message: "URI doesn't seem to be part of this registry." })
274
- }
275
- await this.axios({
276
- ...config,
277
- method: "delete",
278
- url: uri,
279
- })
280
- return true
281
- }
282
-
283
- /**
284
- * Returns a list of annotations.
285
- *
286
- * @param {Object} config
287
- * @param {string} [config.target] target URI
288
- * @returns {Object[]} array of JSKOS annotation objects
289
- */
290
- async getAnnotations({ target, ...config }) {
291
- if (target) {
292
- _.set(config, "params.target", target)
293
- }
294
- return this.axios({
295
- ...config,
296
- method: "get",
297
- url: this._api.annotations,
298
- })
299
- }
300
-
301
- /**
302
- * Creates an annotation.
303
- *
304
- * @param {Object} config
305
- * @param {Object} config.annotation JSKOS annotation
306
- * @returns {Object} JSKOS annotation object
307
- */
308
- async postAnnotation({ annotation, ...config }) {
309
- return this.axios({
310
- ...config,
311
- method: "post",
312
- url: this._api.annotations,
313
- data: annotation,
314
- })
315
- }
316
-
317
- /**
318
- * Overwrites an annotation.
319
- *
320
- * @param {Object} config
321
- * @param {Object} config.annotation JSKOS annotation
322
- * @returns {Object} JSKOS annotation object
323
- */
324
- async putAnnotation({ annotation, ...config }) {
325
- const uri = annotation.id
326
- if (!uri || !uri.startsWith(this._api.annotations)) {
327
- throw new errors.InvalidOrMissingParameterError({ parameter: "annotation", message: "URI doesn't seem to be part of this registry." })
328
- }
329
- return this.axios({
330
- ...config,
331
- method: "put",
332
- url: uri,
333
- data: annotation,
334
- })
335
- }
336
-
337
- /**
338
- * Patches an annotation.
339
- *
340
- * @param {Object} config
341
- * @param {Object} config.annotation JSKOS annotation
342
- * @returns {Object} JSKOS annotation object
343
- */
344
- async patchAnnotation({ annotation, ...config }) {
345
- const uri = annotation.id
346
- if (!uri || !uri.startsWith(this._api.annotations)) {
347
- throw new errors.InvalidOrMissingParameterError({ parameter: "annotation", message: "URI doesn't seem to be part of this registry." })
348
- }
349
- return this.axios({
350
- ...config,
351
- method: "patch",
352
- url: uri,
353
- data: annotation,
354
- })
355
- }
356
-
357
- /**
358
- * Deletes an annotation.
359
- *
360
- * @param {Object} config
361
- * @param {Object} config.annotation JSKOS annotation
362
- * @returns {boolean} `true` if deletion was successful
363
- */
364
- async deleteAnnotation({ annotation, ...config }) {
365
- const uri = annotation.id
366
- if (!uri || !uri.startsWith(this._api.annotations)) {
367
- throw new errors.InvalidOrMissingParameterError({ parameter: "annotation", message: "URI doesn't seem to be part of this registry." })
368
- }
369
- await this.axios({
370
- ...config,
371
- method: "delete",
372
- url: uri,
373
- })
374
- return true
375
- }
376
-
377
- /**
378
- * Returns a list of concordances.
379
- *
380
- * @param {Object} config
381
- * @returns {Object[]} array of JSKOS concordance objects
382
- */
383
- async getConcordances(config) {
384
- return this.axios({
385
- ...config,
386
- method: "get",
387
- url: this._api.concordances,
388
- })
389
- }
390
-
391
- }
392
-
393
- MappingsApiProvider.providerName = "MappingsApi"
394
- MappingsApiProvider.stored = true
395
-
396
- module.exports = MappingsApiProvider
@@ -1,234 +0,0 @@
1
- const BaseProvider = require("./base-provider")
2
- const jskos = require("jskos-tools")
3
- const _ = require("../utils/lodash")
4
- const errors = require("../errors")
5
- const utils = require("../utils")
6
-
7
- // TODO: Modernize.
8
-
9
- /**
10
- * JSKOS Occurrences API.
11
- *
12
- * This class provides access to concept occurrences via JSKOS API in [JSKOS format](https://gbv.github.io/jskos/).
13
- *
14
- * To use it in a registry, specify `provider` as "OccurrencesApi" and provide the API base URL as `api`:
15
- * ```json
16
- * {
17
- * "uri": "http://coli-conc.gbv.de/registry/occurrences",
18
- * "provider": "OccurrencesApi",
19
- * "api": "https://coli-conc.gbv.de/occurrences/api/"
20
- * }
21
- * ```
22
- *
23
- * Additionally, the following JSKOS properties can be provided: `prefLabel`, `notation`, `definition`
24
- *
25
- * @extends BaseProvider
26
- * @category Providers
27
- */
28
- class OccurrencesApiProvider extends BaseProvider {
29
-
30
- /**
31
- * @private
32
- */
33
- _setup() {
34
- this._cache = []
35
- this._occurrencesSupportedSchemes = []
36
- this.has.occurrences = true
37
- this.has.mappings = true
38
- }
39
-
40
- /**
41
- * Returns whether a concept scheme is supported for occurrences.
42
- *
43
- * @private
44
- *
45
- * @param {Object} scheme JSKOS scheme to query
46
- */
47
- async _occurrencesIsSupported(scheme) {
48
- if (this._occurrencesSupportedSchemes && this._occurrencesSupportedSchemes.length) {
49
- // No action needed
50
- } else {
51
- // Load supported schemes from API
52
- try {
53
- const url = utils.concatUrl(this._api.api, "voc")
54
- const data = await this.axios({
55
- method: "get",
56
- url,
57
- })
58
- this._occurrencesSupportedSchemes = data || []
59
- } catch(error) {
60
- // Do nothing so that it is tried again next time
61
- // TODO: Save number of failures?
62
- }
63
- }
64
- let supported = false
65
- for (let supportedScheme of this._occurrencesSupportedSchemes) {
66
- if (jskos.compare(scheme, supportedScheme)) {
67
- supported = true
68
- }
69
- }
70
- return supported
71
- }
72
-
73
- /**
74
- * Wrapper around getOccurrences that converts occurrences into mappings.
75
- *
76
- * @param {Object} config config object for getOccurrences request
77
- * @returns {Object[]} array of JSKOS mapping objects
78
- */
79
- async getMappings(config) {
80
- const occurrences = await this.getOccurrences(config)
81
- const fromScheme = _.get(config, "from.inScheme[0]") || config.fromScheme
82
- const toScheme = _.get(config, "to.inScheme[0]") || config.toScheme
83
- const mappings = []
84
- // Convert occurrences to mappings
85
- for (let occurrence of occurrences) {
86
- if (!occurrence) {
87
- continue
88
- }
89
- let mapping = {}
90
- mapping.from = _.get(occurrence, "memberSet[0]")
91
- if (mapping.from) {
92
- mapping.from = { memberSet: [mapping.from] }
93
- } else {
94
- mapping.from = null
95
- }
96
- mapping.fromScheme = _.get(occurrence, "memberSet[0].inScheme[0]")
97
- mapping.to = _.get(occurrence, "memberSet[1]")
98
- if (mapping.to) {
99
- mapping.to = { memberSet: [mapping.to] }
100
- } else {
101
- mapping.to = { memberSet: [] }
102
- }
103
- mapping.toScheme = _.get(occurrence, "memberSet[1].inScheme[0]")
104
- // Swap sides if necessary
105
- if ((fromScheme && mapping.fromScheme && !jskos.compare(mapping.fromScheme, fromScheme)) || (toScheme && mapping.toScheme && !jskos.compare(mapping.toScheme, toScheme))) {
106
- [mapping.from, mapping.fromScheme, mapping.to, mapping.toScheme] = [mapping.to, mapping.toScheme, mapping.from, mapping.fromScheme]
107
- }
108
- // Set fromScheme/toScheme if necessary
109
- if (!mapping.fromScheme && fromScheme) {
110
- mapping.fromScheme = fromScheme
111
- }
112
- if (!mapping.toScheme && toScheme) {
113
- mapping.toScheme = toScheme
114
- }
115
- mapping.type = [jskos.defaultMappingType.uri]
116
- mapping._occurrence = occurrence
117
- mapping = jskos.addMappingIdentifiers(mapping)
118
- if (occurrence.database) {
119
- mapping.creator = [occurrence.database]
120
- }
121
- mappings.push(mapping)
122
- }
123
- return mappings
124
- }
125
-
126
- /**
127
- * Returns a list of occurrences.
128
- *
129
- * @param {Object} config
130
- * @param {Object} [config.from] JSKOS concept to load occurrences for (from side)
131
- * @param {Object} [config.to] JSKOS concept to load occurrences for (to side)
132
- * @param {Object[]} [config.concepts] list of JSKOS concepts to load occurrences for
133
- * @returns {Object[]} array of JSKOS occurrence objects
134
- */
135
- async getOccurrences({ from, to, concepts, ...config }) {
136
- let promises = []
137
- concepts = (concepts || []).concat([from, to]).filter(c => !!c)
138
- for (let concept of concepts) {
139
- promises.push(this._occurrencesIsSupported(_.get(concept, "inScheme[0]")).then(supported => {
140
- if (supported && concept.uri) {
141
- return concept.uri
142
- } else {
143
- return null
144
- }
145
- }))
146
- }
147
- let uris = await Promise.all(promises)
148
- uris = uris.filter(uri => uri != null)
149
- if (uris.length == 0) {
150
- throw new errors.InvalidOrMissingParameterError({ parameter: "concepts" })
151
- }
152
- promises = []
153
- for (let uri of uris) {
154
- promises.push(this._getOccurrences({
155
- ...config,
156
- params: {
157
- member: uri,
158
- scheme: "*",
159
- threshold: 5,
160
- },
161
- }))
162
- }
163
- // Another request for co-occurrences between two specific concepts
164
- if (uris.length > 1) {
165
- let urisString = uris.join(" ")
166
- promises.push(this._getOccurrences({
167
- ...config,
168
- params: {
169
- member: urisString,
170
- threshold: 5,
171
- },
172
- }))
173
- }
174
- const results = await Promise.all(promises)
175
- let occurrences = _.concat([], ...results)
176
- // Filter duplicates
177
- let existingUris = []
178
- let indexesToDelete = []
179
- for (let i = 0; i < occurrences.length; i += 1) {
180
- let occurrence = occurrences[i]
181
- if (!occurrence) {
182
- continue
183
- }
184
- let uris = occurrence.memberSet.reduce((total, current) => total.concat(current.uri), []).sort().join(" ")
185
- if (existingUris.includes(uris)) {
186
- indexesToDelete.push(i)
187
- } else {
188
- existingUris.push(uris)
189
- }
190
- }
191
- indexesToDelete.forEach(value => {
192
- delete occurrences[value]
193
- })
194
- // Filter null values
195
- occurrences = occurrences.filter(o => o != null)
196
- // Sort occurrences
197
- return occurrences.sort((a, b) => parseInt(b.count || 0) - parseInt(a.count || 0))
198
- }
199
-
200
- /**
201
- * Internal function for getOccurrences that either makes an API request or uses a local cache.
202
- *
203
- * @private
204
- *
205
- * @param {Object} config passthrough of config parameter for axios request
206
- */
207
- async _getOccurrences(config) {
208
- // Use local cache.
209
- let resultsFromCache = this._cache.find(item => {
210
- return _.isEqual(item.config.params, config.params)
211
- })
212
- if (resultsFromCache) {
213
- return resultsFromCache.data
214
- }
215
- const data = await this.axios({
216
- ...config,
217
- method: "get",
218
- url: this._api.api,
219
- })
220
- this._cache.push({
221
- config,
222
- data,
223
- })
224
- if (this._cache.length > 20) {
225
- this._cache = this._cache.slice(this._cache.length - 20)
226
- }
227
- return data
228
- }
229
- }
230
-
231
- OccurrencesApiProvider.providerName = "OccurrencesApi"
232
- OccurrencesApiProvider.stored = false
233
-
234
- module.exports = OccurrencesApiProvider