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.
- package/LICENSE +1 -1
- package/README.md +74 -28
- package/dist/cjs/index.cjs +2673 -0
- package/dist/cocoda-sdk.js +33 -17423
- package/dist/cocoda-sdk.js.LICENSES.txt +105 -86
- package/dist/cocoda-sdk.js.map +7 -0
- package/dist/esm/errors/index.js +46 -0
- package/dist/esm/index.js +9 -0
- package/dist/esm/lib/CocodaSDK.js +269 -0
- package/dist/esm/providers/base-provider.js +368 -0
- package/dist/esm/providers/concept-api-provider.js +278 -0
- package/dist/esm/providers/index.js +20 -0
- package/dist/esm/providers/label-search-suggestion-provider.js +101 -0
- package/dist/esm/providers/loc-api-provider.js +185 -0
- package/dist/esm/providers/local-mappings-provider.js +337 -0
- package/dist/esm/providers/mappings-api-provider.js +264 -0
- package/dist/esm/providers/occurrences-api-provider.js +163 -0
- package/dist/esm/providers/reconciliation-api-provider.js +140 -0
- package/dist/esm/providers/skosmos-api-provider.js +345 -0
- package/{utils → dist/esm/utils}/index.js +40 -53
- package/dist/esm/utils/lodash.js +34 -0
- package/package.json +16 -17
- package/errors/index.js +0 -119
- package/index.js +0 -5
- package/lib/CocodaSDK.js +0 -360
- package/providers/base-provider.js +0 -581
- package/providers/concept-api-provider.js +0 -377
- package/providers/index.js +0 -34
- package/providers/label-search-suggestion-provider.js +0 -219
- package/providers/loc-api-provider.js +0 -275
- package/providers/local-mappings-provider.js +0 -459
- package/providers/mappings-api-provider.js +0 -396
- package/providers/occurrences-api-provider.js +0 -234
- package/providers/reconciliation-api-provider.js +0 -211
- package/providers/skosmos-api-provider.js +0 -441
- package/utils/lodash.js +0 -21
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import BaseProvider from "./base-provider.js";
|
|
2
|
+
import * as _ from "../utils/lodash.js";
|
|
3
|
+
import * as errors from "../errors/index.js";
|
|
4
|
+
import * as utils from "../utils/index.js";
|
|
5
|
+
import jskos from "jskos-tools";
|
|
6
|
+
class ConceptApiProvider extends BaseProvider {
|
|
7
|
+
_prepare() {
|
|
8
|
+
if (this._api.api && this._api.status === void 0) {
|
|
9
|
+
this._api.status = utils.concatUrl(this._api.api, "/status");
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
_setup() {
|
|
13
|
+
if (this._api.api) {
|
|
14
|
+
const endpoints = {
|
|
15
|
+
schemes: "/voc",
|
|
16
|
+
top: "/voc/top",
|
|
17
|
+
concepts: "/voc/concepts",
|
|
18
|
+
data: "/data",
|
|
19
|
+
narrower: "/narrower",
|
|
20
|
+
ancestors: "/ancestors",
|
|
21
|
+
types: "/types",
|
|
22
|
+
suggest: "/suggest",
|
|
23
|
+
search: "/search"
|
|
24
|
+
};
|
|
25
|
+
for (let key of Object.keys(endpoints)) {
|
|
26
|
+
if (this._api[key] === void 0) {
|
|
27
|
+
this._api[key] = utils.concatUrl(this._api.api, endpoints[key]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
this.has.schemes = !!this._api.schemes;
|
|
32
|
+
this.has.top = !!this._api.top;
|
|
33
|
+
this.has.data = !!this._api.data;
|
|
34
|
+
this.has.concepts = !!this._api.concepts || this.has.data;
|
|
35
|
+
this.has.narrower = !!this._api.narrower;
|
|
36
|
+
this.has.ancestors = !!this._api.ancestors;
|
|
37
|
+
this.has.types = !!this._api.types;
|
|
38
|
+
this.has.suggest = !!this._api.suggest;
|
|
39
|
+
this.has.search = !!this._api.search;
|
|
40
|
+
this.has.auth = _.get(this._config, "auth.key") != null;
|
|
41
|
+
this._defaultParams = {
|
|
42
|
+
properties: "uri,prefLabel,notation,inScheme"
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
static _registryConfigForBartocApiConfig({ url } = {}) {
|
|
46
|
+
if (!url) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
api: url
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async _getSchemeUri(scheme) {
|
|
54
|
+
this._approvedSchemes = this._approvedSchemes || [];
|
|
55
|
+
this._rejectedSchemes = this._rejectedSchemes || [];
|
|
56
|
+
let _scheme = this._approvedSchemes.find((s) => jskos.compare(scheme, s));
|
|
57
|
+
if (_scheme) {
|
|
58
|
+
return _scheme.uri;
|
|
59
|
+
}
|
|
60
|
+
if (this._rejectedSchemes.find((s) => jskos.compare(scheme, s))) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const schemes = await this.getSchemes({ uri: jskos.getAllUris(scheme) });
|
|
64
|
+
const resultScheme = schemes.find((s) => jskos.compare(s, scheme));
|
|
65
|
+
if (resultScheme) {
|
|
66
|
+
this._approvedSchemes.push({
|
|
67
|
+
uri: resultScheme.uri,
|
|
68
|
+
identifier: jskos.getAllUris(scheme)
|
|
69
|
+
});
|
|
70
|
+
return resultScheme.uri;
|
|
71
|
+
} else {
|
|
72
|
+
this._rejectedSchemes.push({
|
|
73
|
+
uri: scheme.uri,
|
|
74
|
+
identifier: scheme.identifier
|
|
75
|
+
});
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async getSchemes(config) {
|
|
80
|
+
if (!this._api.schemes) {
|
|
81
|
+
throw new errors.MissingApiUrlError();
|
|
82
|
+
}
|
|
83
|
+
if (Array.isArray(this._api.schemes)) {
|
|
84
|
+
return this._api.schemes;
|
|
85
|
+
}
|
|
86
|
+
const schemes = await this.axios({
|
|
87
|
+
...config,
|
|
88
|
+
method: "get",
|
|
89
|
+
url: this._api.schemes,
|
|
90
|
+
params: {
|
|
91
|
+
...this._defaultParams,
|
|
92
|
+
limit: 500,
|
|
93
|
+
...config.params || {}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
if (Array.isArray(this._jskos.schemes)) {
|
|
97
|
+
return utils.withCustomProps(schemes.filter((s) => jskos.isContainedIn(s, this._jskos.schemes)), schemes);
|
|
98
|
+
} else {
|
|
99
|
+
return schemes;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async getTop({ scheme, ...config }) {
|
|
103
|
+
if (!this._api.top) {
|
|
104
|
+
throw new errors.MissingApiUrlError();
|
|
105
|
+
}
|
|
106
|
+
if (!scheme) {
|
|
107
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: "scheme" });
|
|
108
|
+
}
|
|
109
|
+
const schemeUri = await this._getSchemeUri(scheme);
|
|
110
|
+
if (!schemeUri) {
|
|
111
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: "scheme", message: "Requested vocabulary seems to be unsupported by this API." });
|
|
112
|
+
}
|
|
113
|
+
if (Array.isArray(this._api.top)) {
|
|
114
|
+
return this._api.top;
|
|
115
|
+
}
|
|
116
|
+
return this.axios({
|
|
117
|
+
...config,
|
|
118
|
+
method: "get",
|
|
119
|
+
url: this._api.top,
|
|
120
|
+
params: {
|
|
121
|
+
...this._defaultParams,
|
|
122
|
+
limit: 1e4,
|
|
123
|
+
...config.params || {},
|
|
124
|
+
uri: schemeUri
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
async getConcepts({ concepts, ...config }) {
|
|
129
|
+
if (!this.has.data) {
|
|
130
|
+
throw new errors.MissingApiUrlError();
|
|
131
|
+
}
|
|
132
|
+
if (!concepts) {
|
|
133
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: "concepts" });
|
|
134
|
+
}
|
|
135
|
+
if (!Array.isArray(concepts)) {
|
|
136
|
+
concepts = [concepts];
|
|
137
|
+
}
|
|
138
|
+
let uris = concepts.map((concept) => concept.uri).filter((uri) => uri != null);
|
|
139
|
+
return this.axios({
|
|
140
|
+
...config,
|
|
141
|
+
method: "get",
|
|
142
|
+
url: this._api.data,
|
|
143
|
+
params: {
|
|
144
|
+
...this._defaultParams,
|
|
145
|
+
limit: 500,
|
|
146
|
+
...config.params || {},
|
|
147
|
+
uri: uris.join("|")
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
async getNarrower({ concept, ...config }) {
|
|
152
|
+
if (!this._api.narrower) {
|
|
153
|
+
throw new errors.MissingApiUrlError();
|
|
154
|
+
}
|
|
155
|
+
if (!concept || !concept.uri) {
|
|
156
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: "concept" });
|
|
157
|
+
}
|
|
158
|
+
return this.axios({
|
|
159
|
+
...config,
|
|
160
|
+
method: "get",
|
|
161
|
+
url: this._api.narrower,
|
|
162
|
+
params: {
|
|
163
|
+
...this._defaultParams,
|
|
164
|
+
limit: 1e4,
|
|
165
|
+
...config.params || {},
|
|
166
|
+
uri: concept.uri
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
async getAncestors({ concept, ...config }) {
|
|
171
|
+
if (!this._api.ancestors) {
|
|
172
|
+
throw new errors.MissingApiUrlError();
|
|
173
|
+
}
|
|
174
|
+
if (!concept || !concept.uri) {
|
|
175
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: "concept" });
|
|
176
|
+
}
|
|
177
|
+
return this.axios({
|
|
178
|
+
...config,
|
|
179
|
+
method: "get",
|
|
180
|
+
url: this._api.ancestors,
|
|
181
|
+
params: {
|
|
182
|
+
...this._defaultParams,
|
|
183
|
+
limit: 1e4,
|
|
184
|
+
...config.params || {},
|
|
185
|
+
uri: concept.uri
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
async suggest({ scheme, use = "notation,label", types = [], sort = "score", ...config }) {
|
|
190
|
+
return this._search({
|
|
191
|
+
...config,
|
|
192
|
+
endpoint: "suggest",
|
|
193
|
+
params: {
|
|
194
|
+
...config.params,
|
|
195
|
+
voc: _.get(scheme, "uri", ""),
|
|
196
|
+
type: types.join("|"),
|
|
197
|
+
use,
|
|
198
|
+
sort
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
async search({ scheme, types = [], ...config }) {
|
|
203
|
+
return this._search({
|
|
204
|
+
...config,
|
|
205
|
+
endpoint: "search",
|
|
206
|
+
params: {
|
|
207
|
+
...config.params,
|
|
208
|
+
voc: _.get(scheme, "uri", ""),
|
|
209
|
+
type: types.join("|")
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
async vocSuggest({ use = "notation,label", sort = "score", ...config }) {
|
|
214
|
+
return this._search({
|
|
215
|
+
...config,
|
|
216
|
+
endpoint: "voc-suggest",
|
|
217
|
+
params: {
|
|
218
|
+
...config.params,
|
|
219
|
+
use,
|
|
220
|
+
sort
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
async vocSearch(config) {
|
|
225
|
+
return this._search({
|
|
226
|
+
...config,
|
|
227
|
+
endpoint: "voc-search"
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
async _search({ endpoint, search, limit, offset, params, ...config }) {
|
|
231
|
+
let url = this._api[endpoint];
|
|
232
|
+
if (!url) {
|
|
233
|
+
throw new errors.MissingApiUrlError();
|
|
234
|
+
}
|
|
235
|
+
if (!search) {
|
|
236
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: "search" });
|
|
237
|
+
}
|
|
238
|
+
limit = limit || this._jskos.suggestResultLimit || 100;
|
|
239
|
+
offset = offset || 0;
|
|
240
|
+
url = url.replace("{searchTerms}", search);
|
|
241
|
+
return this.axios({
|
|
242
|
+
...config,
|
|
243
|
+
params: {
|
|
244
|
+
...this._defaultParams,
|
|
245
|
+
...params,
|
|
246
|
+
limit,
|
|
247
|
+
count: limit,
|
|
248
|
+
offset,
|
|
249
|
+
search,
|
|
250
|
+
query: search
|
|
251
|
+
},
|
|
252
|
+
method: "get",
|
|
253
|
+
url
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
async getTypes({ scheme, ...config }) {
|
|
257
|
+
if (!this._api.types) {
|
|
258
|
+
throw new errors.MissingApiUrlError();
|
|
259
|
+
}
|
|
260
|
+
if (Array.isArray(this._api.types)) {
|
|
261
|
+
return this._api.types;
|
|
262
|
+
}
|
|
263
|
+
const schemeUri = scheme && await this._getSchemeUri(scheme);
|
|
264
|
+
if (schemeUri) {
|
|
265
|
+
_.set(config, "params.uri", schemeUri);
|
|
266
|
+
}
|
|
267
|
+
return this.axios({
|
|
268
|
+
...config,
|
|
269
|
+
method: "get",
|
|
270
|
+
url: this._api.types
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
ConceptApiProvider.providerName = "ConceptApi";
|
|
275
|
+
ConceptApiProvider.providerType = "http://bartoc.org/api-type/jskos";
|
|
276
|
+
export {
|
|
277
|
+
ConceptApiProvider as default
|
|
278
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import BaseProvider from "./base-provider.js";
|
|
2
|
+
import LocalMappingsProvider from "./local-mappings-provider.js";
|
|
3
|
+
import MappingsApiProvider from "./mappings-api-provider.js";
|
|
4
|
+
import OccurrencesApiProvider from "./occurrences-api-provider.js";
|
|
5
|
+
import ConceptApiProvider from "./concept-api-provider.js";
|
|
6
|
+
import ReconciliationApiProvider from "./reconciliation-api-provider.js";
|
|
7
|
+
import LabelSearchSuggestionProvider from "./label-search-suggestion-provider.js";
|
|
8
|
+
import SkosmosApiProvider from "./skosmos-api-provider.js";
|
|
9
|
+
import LocApiProvider from "./loc-api-provider.js";
|
|
10
|
+
export {
|
|
11
|
+
BaseProvider,
|
|
12
|
+
ConceptApiProvider,
|
|
13
|
+
LabelSearchSuggestionProvider,
|
|
14
|
+
LocApiProvider,
|
|
15
|
+
LocalMappingsProvider,
|
|
16
|
+
MappingsApiProvider,
|
|
17
|
+
OccurrencesApiProvider,
|
|
18
|
+
ReconciliationApiProvider,
|
|
19
|
+
SkosmosApiProvider
|
|
20
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import BaseProvider from "./base-provider.js";
|
|
2
|
+
import jskos from "jskos-tools";
|
|
3
|
+
import * as _ from "../utils/lodash.js";
|
|
4
|
+
import * as errors from "../errors/index.js";
|
|
5
|
+
class LabelSearchSuggestionProvider extends BaseProvider {
|
|
6
|
+
_setup() {
|
|
7
|
+
this._cache = [];
|
|
8
|
+
this.has.mappings = true;
|
|
9
|
+
}
|
|
10
|
+
supportsScheme(scheme) {
|
|
11
|
+
return _.get(scheme, "_registry.has.search", false);
|
|
12
|
+
}
|
|
13
|
+
async getMappings({ from, to, mode, selected, limit = 10, ...config }) {
|
|
14
|
+
if (mode != "or") {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
if (!selected) {
|
|
18
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: "selected" });
|
|
19
|
+
}
|
|
20
|
+
let promises = [];
|
|
21
|
+
if (from && this.supportsScheme(selected.scheme[false])) {
|
|
22
|
+
promises.push(this._getMappings({ ...config, concept: from, sourceScheme: selected.scheme[true], targetScheme: selected.scheme[false], limit }));
|
|
23
|
+
} else {
|
|
24
|
+
promises.push(Promise.resolve([]));
|
|
25
|
+
}
|
|
26
|
+
if (to && this.supportsScheme(selected.scheme[true])) {
|
|
27
|
+
promises.push(this._getMappings({ ...config, concept: to, sourceScheme: selected.scheme[false], targetScheme: selected.scheme[true], limit, swap: true }));
|
|
28
|
+
} else {
|
|
29
|
+
promises.push(Promise.resolve([]));
|
|
30
|
+
}
|
|
31
|
+
let [fromResult, toResult] = await Promise.all(promises);
|
|
32
|
+
toResult = toResult.filter((m) => !fromResult.find((n) => jskos.compareMappingMembers(m, n)));
|
|
33
|
+
while (fromResult.length + toResult.length > limit) {
|
|
34
|
+
if (toResult.length >= fromResult.length) {
|
|
35
|
+
toResult = toResult.slice(0, -1);
|
|
36
|
+
} else {
|
|
37
|
+
fromResult = fromResult.slice(0, -1);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return _.union(fromResult, toResult);
|
|
41
|
+
}
|
|
42
|
+
async _getMappings({ concept, sourceScheme, targetScheme, limit, swap = false, ...config }) {
|
|
43
|
+
if (!concept || !sourceScheme || !targetScheme) {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
if (jskos.compare(sourceScheme, targetScheme)) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
let label = jskos.prefLabel(concept, {
|
|
50
|
+
fallbackToUri: false,
|
|
51
|
+
language: this.languages[0] || this._defaultLanguages[0]
|
|
52
|
+
});
|
|
53
|
+
if (!label) {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
const results = await this._getResults({ ...config, label, targetScheme, limit });
|
|
57
|
+
let mappings = results.map((result) => ({
|
|
58
|
+
fromScheme: sourceScheme,
|
|
59
|
+
from: { memberSet: [concept] },
|
|
60
|
+
toScheme: targetScheme,
|
|
61
|
+
to: { memberSet: [result] },
|
|
62
|
+
type: ["http://www.w3.org/2004/02/skos/core#mappingRelation"]
|
|
63
|
+
}));
|
|
64
|
+
if (swap) {
|
|
65
|
+
mappings = mappings.map((mapping) => Object.assign(mapping, {
|
|
66
|
+
fromScheme: mapping.toScheme,
|
|
67
|
+
from: mapping.to,
|
|
68
|
+
toScheme: mapping.fromScheme,
|
|
69
|
+
to: mapping.from
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
return mappings;
|
|
73
|
+
}
|
|
74
|
+
async _getResults({ label, targetScheme, limit, ...config }) {
|
|
75
|
+
let resultsFromCache = (this._cache[targetScheme.uri] || {})[label];
|
|
76
|
+
if (resultsFromCache && resultsFromCache._limit >= limit) {
|
|
77
|
+
return resultsFromCache;
|
|
78
|
+
}
|
|
79
|
+
const registry = _.get(targetScheme, "_registry");
|
|
80
|
+
if (!registry || !registry.has.search) {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
const data = await registry.search({
|
|
84
|
+
...config,
|
|
85
|
+
search: label,
|
|
86
|
+
scheme: targetScheme,
|
|
87
|
+
limit
|
|
88
|
+
});
|
|
89
|
+
if (!this._cache[targetScheme.uri]) {
|
|
90
|
+
this._cache[targetScheme.uri] = {};
|
|
91
|
+
}
|
|
92
|
+
this._cache[targetScheme.uri][label] = data;
|
|
93
|
+
this._cache[targetScheme.uri][label]._limit = limit;
|
|
94
|
+
return data;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
LabelSearchSuggestionProvider.providerName = "LabelSearchSuggestion";
|
|
98
|
+
LabelSearchSuggestionProvider.stored = false;
|
|
99
|
+
export {
|
|
100
|
+
LabelSearchSuggestionProvider as default
|
|
101
|
+
};
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import BaseProvider from "./base-provider.js";
|
|
2
|
+
import * as errors from "../errors/index.js";
|
|
3
|
+
import jskos from "jskos-tools";
|
|
4
|
+
import axios from "axios";
|
|
5
|
+
const locUriPrefix = "http://id.loc.gov/authorities/";
|
|
6
|
+
const supportedSchemes = [
|
|
7
|
+
{
|
|
8
|
+
uri: `${locUriPrefix}subjects`,
|
|
9
|
+
identifier: [
|
|
10
|
+
"http://bartoc.org/en/node/454"
|
|
11
|
+
],
|
|
12
|
+
notation: ["LCSH"],
|
|
13
|
+
concepts: [null],
|
|
14
|
+
topConcepts: []
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
uri: `${locUriPrefix}names`,
|
|
18
|
+
identifier: [
|
|
19
|
+
"http://bartoc.org/en/node/18536"
|
|
20
|
+
],
|
|
21
|
+
notation: ["LCNAF"],
|
|
22
|
+
concepts: [null],
|
|
23
|
+
topConcepts: []
|
|
24
|
+
}
|
|
25
|
+
];
|
|
26
|
+
const lccUri = `${locUriPrefix}classification`;
|
|
27
|
+
function madsToJskosItem(data) {
|
|
28
|
+
const item = {};
|
|
29
|
+
item.uri = data["@id"];
|
|
30
|
+
item.notation = (data["http://www.loc.gov/mads/rdf/v1#code"] || []).map((n) => n["@value"]);
|
|
31
|
+
const prefLabelArray = data["http://www.loc.gov/mads/rdf/v1#authoritativeLabel"] || data["http://www.w3.org/2000/01/rdf-schema#label"] || [];
|
|
32
|
+
if (prefLabelArray.length) {
|
|
33
|
+
item.prefLabel = {};
|
|
34
|
+
item.prefLabel[prefLabelArray[0]["@language"] || "en"] = prefLabelArray[0]["@value"];
|
|
35
|
+
}
|
|
36
|
+
const altLabelArray = data["http://www.w3.org/2004/02/skos/core#altLabel"] || [];
|
|
37
|
+
if (altLabelArray.length) {
|
|
38
|
+
item.altLabel = { en: altLabelArray.map((l) => l["@value"]) };
|
|
39
|
+
}
|
|
40
|
+
for (let definition of data["http://www.w3.org/2000/01/rdf-schema#comment"] || []) {
|
|
41
|
+
item.definition = item.definition || {};
|
|
42
|
+
item.definition.en = item.definition.en || [];
|
|
43
|
+
item.definition.en.push(definition["@value"]);
|
|
44
|
+
}
|
|
45
|
+
return item;
|
|
46
|
+
}
|
|
47
|
+
function madsToJskosScheme(data) {
|
|
48
|
+
const scheme = madsToJskosItem(data);
|
|
49
|
+
scheme.namespace = scheme.uri + "/";
|
|
50
|
+
scheme.type = ["http://www.w3.org/2004/02/skos/core#ConceptScheme"];
|
|
51
|
+
return scheme;
|
|
52
|
+
}
|
|
53
|
+
const schemeNamespaceFilter = (scheme) => (c) => {
|
|
54
|
+
if (!c || !scheme || !scheme.namespace) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
return c.uri.startsWith(scheme.namespace);
|
|
58
|
+
};
|
|
59
|
+
function madsToJskosConcept(data, { scheme }) {
|
|
60
|
+
const concept = madsToJskosItem(data);
|
|
61
|
+
concept.type = ["http://www.w3.org/2004/02/skos/core#Concept"];
|
|
62
|
+
concept.inScheme = scheme ? [scheme] : (data["http://www.loc.gov/mads/rdf/v1#isMemberOfMADSScheme"] || []).map((s) => supportedSchemes.find((s2) => s2.uri === s["@id"]));
|
|
63
|
+
if (!concept.inScheme.length || !concept.inScheme[0]) {
|
|
64
|
+
delete concept.inScheme;
|
|
65
|
+
}
|
|
66
|
+
const narrower = data["http://www.loc.gov/mads/rdf/v1#hasNarrowerAuthority"] || jskos.compare(concept.inScheme[0], { uri: lccUri }) && data["http://www.loc.gov/mads/rdf/v1#hasMADSCollectionMember"] || [];
|
|
67
|
+
concept.narrower = narrower.map((n) => ({ uri: n["@id"] })).filter(schemeNamespaceFilter(concept.inScheme && concept.inScheme[0]));
|
|
68
|
+
const broader = data["http://www.loc.gov/mads/rdf/v1#hasBroaderAuthority"] || jskos.compare(concept.inScheme[0], { uri: lccUri }) && data["http://www.loc.gov/mads/rdf/v1#isMemberOfMADSCollection"] || [];
|
|
69
|
+
concept.broader = broader.map((n) => ({ uri: n["@id"] })).filter(schemeNamespaceFilter(concept.inScheme && concept.inScheme[0]));
|
|
70
|
+
return concept;
|
|
71
|
+
}
|
|
72
|
+
class LocApiProvider extends BaseProvider {
|
|
73
|
+
_setup() {
|
|
74
|
+
this.has.schemes = true;
|
|
75
|
+
this.has.top = false;
|
|
76
|
+
this.has.data = true;
|
|
77
|
+
this.has.concepts = true;
|
|
78
|
+
this.has.narrower = true;
|
|
79
|
+
this.has.ancestors = false;
|
|
80
|
+
this.has.suggest = true;
|
|
81
|
+
this.has.search = true;
|
|
82
|
+
}
|
|
83
|
+
static _registryConfigForBartocApiConfig({ scheme } = {}) {
|
|
84
|
+
if (!scheme || !supportedSchemes.find((s) => jskos.compare(s, scheme))) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
schemes: [scheme]
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
async getSchemes() {
|
|
92
|
+
const schemes = [];
|
|
93
|
+
for (let scheme of await Promise.all(supportedSchemes.filter((s) => !this.schemes || !this.schemes.length || this.schemes.find((s2) => jskos.compare(s, s2))).map((s) => axios({
|
|
94
|
+
method: "get",
|
|
95
|
+
url: `${s.uri.replace("http:", "https:")}.json`
|
|
96
|
+
}).then(({ status, data }) => {
|
|
97
|
+
if (status === 200) {
|
|
98
|
+
let scheme2 = data.find((d) => s.uri === d["@id"]);
|
|
99
|
+
if (scheme2) {
|
|
100
|
+
scheme2 = jskos.merge(madsToJskosScheme(scheme2), s);
|
|
101
|
+
scheme2.topConcepts = (scheme2.topConcepts || []).filter((c) => c);
|
|
102
|
+
return scheme2;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
})))) {
|
|
107
|
+
if (scheme) {
|
|
108
|
+
schemes.push(scheme);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return schemes;
|
|
112
|
+
}
|
|
113
|
+
async getConcepts({ concepts }) {
|
|
114
|
+
if (!Array.isArray(concepts)) {
|
|
115
|
+
concepts = [concepts];
|
|
116
|
+
}
|
|
117
|
+
const resultConcepts = [];
|
|
118
|
+
for (let concept of await Promise.all(concepts.map((c) => axios({
|
|
119
|
+
method: "get",
|
|
120
|
+
url: `${c.uri.replace("http:", "https:")}.json`
|
|
121
|
+
}).then(({ status, data }) => {
|
|
122
|
+
if (status === 200) {
|
|
123
|
+
let concept2 = data.find((d) => c.uri === d["@id"]);
|
|
124
|
+
if (concept2) {
|
|
125
|
+
return madsToJskosConcept(concept2, { scheme: c.inScheme && c.inScheme[0] });
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
})))) {
|
|
130
|
+
if (concept) {
|
|
131
|
+
resultConcepts.push(concept);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return resultConcepts;
|
|
135
|
+
}
|
|
136
|
+
async suggest(config) {
|
|
137
|
+
const results = await this.search(config);
|
|
138
|
+
return [
|
|
139
|
+
config.search,
|
|
140
|
+
results.map((c) => {
|
|
141
|
+
let string = "";
|
|
142
|
+
const notation = jskos.notation(c);
|
|
143
|
+
if (notation) {
|
|
144
|
+
string += notation + " ";
|
|
145
|
+
}
|
|
146
|
+
string += jskos.prefLabel(c, { fallbackToUri: string === "" });
|
|
147
|
+
return string;
|
|
148
|
+
}),
|
|
149
|
+
[],
|
|
150
|
+
results.map((c) => c.uri)
|
|
151
|
+
];
|
|
152
|
+
}
|
|
153
|
+
async search({ search, scheme, limit, offset }) {
|
|
154
|
+
const schemeUri = jskos.getAllUris(scheme).find((uri) => uri.startsWith(locUriPrefix));
|
|
155
|
+
if (!schemeUri || !supportedSchemes.find((s) => jskos.compare(s, { uri: schemeUri }))) {
|
|
156
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: "scheme", message: "provided scheme is not supported (yet)" });
|
|
157
|
+
}
|
|
158
|
+
if (!search) {
|
|
159
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: "search", message: "parameter is empty or missing" });
|
|
160
|
+
}
|
|
161
|
+
limit = limit || this._jskos.suggestResultLimit || 100;
|
|
162
|
+
offset = offset || 0;
|
|
163
|
+
const { data } = await axios({
|
|
164
|
+
method: "get",
|
|
165
|
+
url: `${schemeUri}/suggest2`.replace("http:", "https:"),
|
|
166
|
+
params: {
|
|
167
|
+
q: search,
|
|
168
|
+
count: limit || 100,
|
|
169
|
+
offset,
|
|
170
|
+
searchtype: "keyword"
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
return (data.hits || []).map((d) => ({
|
|
174
|
+
uri: d.uri,
|
|
175
|
+
notation: [d.token],
|
|
176
|
+
prefLabel: { en: d.aLabel },
|
|
177
|
+
inScheme: [scheme]
|
|
178
|
+
})).filter(schemeNamespaceFilter(scheme));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
LocApiProvider.providerName = "LocApi";
|
|
182
|
+
LocApiProvider.providerType = "http://bartoc.org/api-type/loc";
|
|
183
|
+
export {
|
|
184
|
+
LocApiProvider as default
|
|
185
|
+
};
|