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,163 @@
|
|
|
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
|
+
import * as utils from "../utils/index.js";
|
|
6
|
+
class OccurrencesApiProvider extends BaseProvider {
|
|
7
|
+
_setup() {
|
|
8
|
+
this._cache = [];
|
|
9
|
+
this._occurrencesSupportedSchemes = [];
|
|
10
|
+
this.has.occurrences = true;
|
|
11
|
+
this.has.mappings = true;
|
|
12
|
+
}
|
|
13
|
+
async _occurrencesIsSupported(scheme) {
|
|
14
|
+
if (this._occurrencesSupportedSchemes && this._occurrencesSupportedSchemes.length) {
|
|
15
|
+
} else {
|
|
16
|
+
try {
|
|
17
|
+
const url = utils.concatUrl(this._api.api, "voc");
|
|
18
|
+
const data = await this.axios({
|
|
19
|
+
method: "get",
|
|
20
|
+
url
|
|
21
|
+
});
|
|
22
|
+
this._occurrencesSupportedSchemes = data || [];
|
|
23
|
+
} catch (error) {
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
let supported = false;
|
|
27
|
+
for (let supportedScheme of this._occurrencesSupportedSchemes) {
|
|
28
|
+
if (jskos.compare(scheme, supportedScheme)) {
|
|
29
|
+
supported = true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return supported;
|
|
33
|
+
}
|
|
34
|
+
async getMappings(config) {
|
|
35
|
+
const occurrences = await this.getOccurrences(config);
|
|
36
|
+
const fromScheme = _.get(config, "from.inScheme[0]") || config.fromScheme;
|
|
37
|
+
const toScheme = _.get(config, "to.inScheme[0]") || config.toScheme;
|
|
38
|
+
const mappings = [];
|
|
39
|
+
for (let occurrence of occurrences) {
|
|
40
|
+
if (!occurrence) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
let mapping = {};
|
|
44
|
+
mapping.from = _.get(occurrence, "memberSet[0]");
|
|
45
|
+
if (mapping.from) {
|
|
46
|
+
mapping.from = { memberSet: [mapping.from] };
|
|
47
|
+
} else {
|
|
48
|
+
mapping.from = null;
|
|
49
|
+
}
|
|
50
|
+
mapping.fromScheme = _.get(occurrence, "memberSet[0].inScheme[0]");
|
|
51
|
+
mapping.to = _.get(occurrence, "memberSet[1]");
|
|
52
|
+
if (mapping.to) {
|
|
53
|
+
mapping.to = { memberSet: [mapping.to] };
|
|
54
|
+
} else {
|
|
55
|
+
mapping.to = { memberSet: [] };
|
|
56
|
+
}
|
|
57
|
+
mapping.toScheme = _.get(occurrence, "memberSet[1].inScheme[0]");
|
|
58
|
+
if (fromScheme && mapping.fromScheme && !jskos.compare(mapping.fromScheme, fromScheme) || toScheme && mapping.toScheme && !jskos.compare(mapping.toScheme, toScheme)) {
|
|
59
|
+
[mapping.from, mapping.fromScheme, mapping.to, mapping.toScheme] = [mapping.to, mapping.toScheme, mapping.from, mapping.fromScheme];
|
|
60
|
+
}
|
|
61
|
+
if (!mapping.fromScheme && fromScheme) {
|
|
62
|
+
mapping.fromScheme = fromScheme;
|
|
63
|
+
}
|
|
64
|
+
if (!mapping.toScheme && toScheme) {
|
|
65
|
+
mapping.toScheme = toScheme;
|
|
66
|
+
}
|
|
67
|
+
mapping.type = [jskos.defaultMappingType.uri];
|
|
68
|
+
mapping._occurrence = occurrence;
|
|
69
|
+
mapping = jskos.addMappingIdentifiers(mapping);
|
|
70
|
+
if (occurrence.database) {
|
|
71
|
+
mapping.creator = [occurrence.database];
|
|
72
|
+
}
|
|
73
|
+
mappings.push(mapping);
|
|
74
|
+
}
|
|
75
|
+
return mappings;
|
|
76
|
+
}
|
|
77
|
+
async getOccurrences({ from, to, concepts, ...config }) {
|
|
78
|
+
let promises = [];
|
|
79
|
+
concepts = (concepts || []).concat([from, to]).filter((c) => !!c);
|
|
80
|
+
for (let concept of concepts) {
|
|
81
|
+
promises.push(this._occurrencesIsSupported(_.get(concept, "inScheme[0]")).then((supported) => {
|
|
82
|
+
if (supported && concept.uri) {
|
|
83
|
+
return concept.uri;
|
|
84
|
+
} else {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
let uris = await Promise.all(promises);
|
|
90
|
+
uris = uris.filter((uri) => uri != null);
|
|
91
|
+
if (uris.length == 0) {
|
|
92
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: "concepts" });
|
|
93
|
+
}
|
|
94
|
+
promises = [];
|
|
95
|
+
for (let uri of uris) {
|
|
96
|
+
promises.push(this._getOccurrences({
|
|
97
|
+
...config,
|
|
98
|
+
params: {
|
|
99
|
+
member: uri,
|
|
100
|
+
scheme: "*",
|
|
101
|
+
threshold: 5
|
|
102
|
+
}
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
if (uris.length > 1) {
|
|
106
|
+
let urisString = uris.join(" ");
|
|
107
|
+
promises.push(this._getOccurrences({
|
|
108
|
+
...config,
|
|
109
|
+
params: {
|
|
110
|
+
member: urisString,
|
|
111
|
+
threshold: 5
|
|
112
|
+
}
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
const results = await Promise.all(promises);
|
|
116
|
+
let occurrences = _.concat([], ...results);
|
|
117
|
+
let existingUris = [];
|
|
118
|
+
let indexesToDelete = [];
|
|
119
|
+
for (let i = 0; i < occurrences.length; i += 1) {
|
|
120
|
+
let occurrence = occurrences[i];
|
|
121
|
+
if (!occurrence) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
let uris2 = occurrence.memberSet.reduce((total, current) => total.concat(current.uri), []).sort().join(" ");
|
|
125
|
+
if (existingUris.includes(uris2)) {
|
|
126
|
+
indexesToDelete.push(i);
|
|
127
|
+
} else {
|
|
128
|
+
existingUris.push(uris2);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
indexesToDelete.forEach((value) => {
|
|
132
|
+
delete occurrences[value];
|
|
133
|
+
});
|
|
134
|
+
occurrences = occurrences.filter((o) => o != null);
|
|
135
|
+
return occurrences.sort((a, b) => parseInt(b.count || 0) - parseInt(a.count || 0));
|
|
136
|
+
}
|
|
137
|
+
async _getOccurrences(config) {
|
|
138
|
+
let resultsFromCache = this._cache.find((item) => {
|
|
139
|
+
return _.isEqual(item.config.params, config.params);
|
|
140
|
+
});
|
|
141
|
+
if (resultsFromCache) {
|
|
142
|
+
return resultsFromCache.data;
|
|
143
|
+
}
|
|
144
|
+
const data = await this.axios({
|
|
145
|
+
...config,
|
|
146
|
+
method: "get",
|
|
147
|
+
url: this._api.api
|
|
148
|
+
});
|
|
149
|
+
this._cache.push({
|
|
150
|
+
config,
|
|
151
|
+
data
|
|
152
|
+
});
|
|
153
|
+
if (this._cache.length > 20) {
|
|
154
|
+
this._cache = this._cache.slice(this._cache.length - 20);
|
|
155
|
+
}
|
|
156
|
+
return data;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
OccurrencesApiProvider.providerName = "OccurrencesApi";
|
|
160
|
+
OccurrencesApiProvider.stored = false;
|
|
161
|
+
export {
|
|
162
|
+
OccurrencesApiProvider as default
|
|
163
|
+
};
|
|
@@ -0,0 +1,140 @@
|
|
|
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 ReconciliationApiProvider extends BaseProvider {
|
|
6
|
+
_setup() {
|
|
7
|
+
this.has.mappings = true;
|
|
8
|
+
this._cache = [];
|
|
9
|
+
}
|
|
10
|
+
async getMappings({ from, to, mode, ...config }) {
|
|
11
|
+
let schemes = [];
|
|
12
|
+
if (_.isArray(this.schemes)) {
|
|
13
|
+
schemes = this.schemes;
|
|
14
|
+
}
|
|
15
|
+
let swap;
|
|
16
|
+
let concept;
|
|
17
|
+
let fromConceptScheme = _.get(from, "inScheme[0]");
|
|
18
|
+
let toConceptScheme = _.get(to, "inScheme[0]");
|
|
19
|
+
let fromScheme;
|
|
20
|
+
let toScheme;
|
|
21
|
+
if (!from || jskos.isContainedIn(fromConceptScheme, schemes)) {
|
|
22
|
+
swap = true;
|
|
23
|
+
concept = to;
|
|
24
|
+
fromScheme = toConceptScheme;
|
|
25
|
+
toScheme = schemes.find((scheme) => jskos.compare(scheme, fromConceptScheme)) || schemes[0];
|
|
26
|
+
} else {
|
|
27
|
+
swap = false;
|
|
28
|
+
concept = from;
|
|
29
|
+
fromScheme = fromConceptScheme;
|
|
30
|
+
toScheme = schemes.find((scheme) => jskos.compare(scheme, toConceptScheme)) || schemes[0];
|
|
31
|
+
}
|
|
32
|
+
if (mode != "or") {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
if (!this._api.api) {
|
|
36
|
+
throw new errors.MissingApiUrlError();
|
|
37
|
+
}
|
|
38
|
+
if (!concept) {
|
|
39
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: swap ? "to" : "from" });
|
|
40
|
+
}
|
|
41
|
+
let language = jskos.languagePreference.selectLanguage(concept.prefLabel);
|
|
42
|
+
if (!language) {
|
|
43
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: swap ? "to" : "from", message: "Missing language" });
|
|
44
|
+
}
|
|
45
|
+
let altLabels = _.get(concept, `altLabel.${language}`, []);
|
|
46
|
+
if (_.isString(altLabels)) {
|
|
47
|
+
altLabels = [altLabels];
|
|
48
|
+
}
|
|
49
|
+
let prefLabel = _.get(concept, `prefLabel.${language}`);
|
|
50
|
+
let labels = altLabels.concat([prefLabel]);
|
|
51
|
+
labels = [prefLabel];
|
|
52
|
+
let { url, data: results } = await this._getReconciliationResults({ ...config, labels, language });
|
|
53
|
+
results = [].concat(...Object.values(results).map((value) => value.result)).filter((r) => r);
|
|
54
|
+
results = results.sort((a, b) => {
|
|
55
|
+
if (a.score != b.score) {
|
|
56
|
+
return b.score - a.score;
|
|
57
|
+
}
|
|
58
|
+
if (a.match != b.match) {
|
|
59
|
+
if (a.match) {
|
|
60
|
+
return -1;
|
|
61
|
+
} else {
|
|
62
|
+
return 1;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return a.id.length - b.id.length;
|
|
66
|
+
});
|
|
67
|
+
let namespace = _.get(toScheme, "namespace", "");
|
|
68
|
+
let mappings = results.map((result) => ({
|
|
69
|
+
fromScheme,
|
|
70
|
+
from: { memberSet: [concept] },
|
|
71
|
+
toScheme,
|
|
72
|
+
to: {
|
|
73
|
+
memberSet: [
|
|
74
|
+
{
|
|
75
|
+
uri: namespace + result.id
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
type: [
|
|
80
|
+
result.match ? "http://www.w3.org/2004/02/skos/core#exactMatch" : result.score >= 80 ? "http://www.w3.org/2004/02/skos/core#closeMatch" : "http://www.w3.org/2004/02/skos/core#mappingRelation"
|
|
81
|
+
]
|
|
82
|
+
}));
|
|
83
|
+
if (swap) {
|
|
84
|
+
mappings = mappings.map((mapping) => Object.assign(mapping, {
|
|
85
|
+
fromScheme: mapping.toScheme,
|
|
86
|
+
from: mapping.to,
|
|
87
|
+
toScheme: mapping.fromScheme,
|
|
88
|
+
to: mapping.from
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
mappings._url = url;
|
|
92
|
+
return mappings;
|
|
93
|
+
}
|
|
94
|
+
async _getReconciliationResults({ labels, language, ...config }) {
|
|
95
|
+
labels = labels.sort();
|
|
96
|
+
let resultsFromCache = this._cache.find((item) => {
|
|
97
|
+
return _.isEqual(item.labels, labels) && item.language == language;
|
|
98
|
+
});
|
|
99
|
+
if (resultsFromCache) {
|
|
100
|
+
return resultsFromCache;
|
|
101
|
+
}
|
|
102
|
+
let queries = {};
|
|
103
|
+
let index = 0;
|
|
104
|
+
for (let label of labels) {
|
|
105
|
+
queries[`q${index}`] = {
|
|
106
|
+
query: label
|
|
107
|
+
};
|
|
108
|
+
index += 1;
|
|
109
|
+
}
|
|
110
|
+
let url = this._api.api;
|
|
111
|
+
if (language) {
|
|
112
|
+
url = url.replace("{language}", language);
|
|
113
|
+
}
|
|
114
|
+
const encodedData = `queries=${encodeURIComponent(JSON.stringify(queries))}`;
|
|
115
|
+
_.set(config, ["headers", "Content-Type"], "application/x-www-form-urlencoded");
|
|
116
|
+
let data = await this.axios({
|
|
117
|
+
...config,
|
|
118
|
+
method: "post",
|
|
119
|
+
url,
|
|
120
|
+
data: encodedData
|
|
121
|
+
});
|
|
122
|
+
data = data || {};
|
|
123
|
+
let newCacheEntry = {
|
|
124
|
+
labels,
|
|
125
|
+
language,
|
|
126
|
+
data,
|
|
127
|
+
url: `${url}${url.includes("?") ? "&" : "?"}${encodedData}`
|
|
128
|
+
};
|
|
129
|
+
this._cache.push(newCacheEntry);
|
|
130
|
+
if (this._cache.length > 20) {
|
|
131
|
+
this._cache = this._cache.slice(this._cache.length - 20);
|
|
132
|
+
}
|
|
133
|
+
return newCacheEntry;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
ReconciliationApiProvider.providerName = "ReconciliationApi";
|
|
137
|
+
ReconciliationApiProvider.stored = false;
|
|
138
|
+
export {
|
|
139
|
+
ReconciliationApiProvider as default
|
|
140
|
+
};
|
|
@@ -0,0 +1,345 @@
|
|
|
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 SkosmosApiProvider extends BaseProvider {
|
|
6
|
+
_setup() {
|
|
7
|
+
this.has.schemes = true;
|
|
8
|
+
this.has.top = false;
|
|
9
|
+
this.has.data = true;
|
|
10
|
+
this.has.concepts = true;
|
|
11
|
+
this.has.narrower = true;
|
|
12
|
+
this.has.ancestors = true;
|
|
13
|
+
this.has.types = true;
|
|
14
|
+
this.has.suggest = true;
|
|
15
|
+
this.has.search = true;
|
|
16
|
+
for (let scheme of this.schemes) {
|
|
17
|
+
scheme.concepts = [null];
|
|
18
|
+
scheme.topConcepts = [];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
static _registryConfigForBartocApiConfig({ url, scheme } = {}) {
|
|
22
|
+
if (!url || !scheme) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const config = {};
|
|
26
|
+
const match = url.match(/(.+\/)([^/]+)\/$/);
|
|
27
|
+
if (!match) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
config.api = match[1] + "rest/v1/";
|
|
31
|
+
scheme.VOCID = match[2];
|
|
32
|
+
config.schemes = [scheme];
|
|
33
|
+
return config;
|
|
34
|
+
}
|
|
35
|
+
get _language() {
|
|
36
|
+
return this.languages[0] || this._defaultLanguages[0] || "en";
|
|
37
|
+
}
|
|
38
|
+
_getApiUrl(scheme, endpoint, params) {
|
|
39
|
+
if (!scheme || !scheme.VOCID) {
|
|
40
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: "scheme", message: "Missing scheme or VOCID property on scheme" });
|
|
41
|
+
}
|
|
42
|
+
endpoint = endpoint || "";
|
|
43
|
+
params = params || {};
|
|
44
|
+
if (!params.lang) {
|
|
45
|
+
params.lang = this._language;
|
|
46
|
+
}
|
|
47
|
+
const paramString = Object.keys(params).map((k) => `${k}=${encodeURIComponent(params[k])}`).join("&");
|
|
48
|
+
return `${this._api.api}${scheme.VOCID}${endpoint}${paramString ? "?" + paramString : ""}`;
|
|
49
|
+
}
|
|
50
|
+
_getDataUrl(concept, { addFormatParameter = true } = {}) {
|
|
51
|
+
const scheme = _.get(concept, "inScheme[0]");
|
|
52
|
+
if (!concept || !concept.uri) {
|
|
53
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: "concept", message: "Missing concept URI" });
|
|
54
|
+
}
|
|
55
|
+
return this._getApiUrl(scheme, "/data", addFormatParameter ? { format: "application/json" } : {});
|
|
56
|
+
}
|
|
57
|
+
async _getSchemeUri(scheme) {
|
|
58
|
+
this._approvedSchemes = this._approvedSchemes || [];
|
|
59
|
+
this._rejectedSchemes = this._rejectedSchemes || [];
|
|
60
|
+
let _scheme = this._approvedSchemes.find((s) => jskos.compare(scheme, s));
|
|
61
|
+
if (_scheme) {
|
|
62
|
+
return _scheme.uri;
|
|
63
|
+
}
|
|
64
|
+
if (this._rejectedSchemes.find((s) => jskos.compare(scheme, s))) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const url = this._getApiUrl(scheme, "/");
|
|
68
|
+
const data = await this.axios({
|
|
69
|
+
method: "get",
|
|
70
|
+
url
|
|
71
|
+
});
|
|
72
|
+
const resultScheme = data.conceptschemes.find((s) => jskos.compare(s, scheme));
|
|
73
|
+
if (resultScheme) {
|
|
74
|
+
this._approvedSchemes.push({
|
|
75
|
+
uri: resultScheme.uri,
|
|
76
|
+
identifier: jskos.getAllUris(scheme)
|
|
77
|
+
});
|
|
78
|
+
return resultScheme.uri;
|
|
79
|
+
} else {
|
|
80
|
+
this._rejectedSchemes.push({
|
|
81
|
+
uri: scheme.uri,
|
|
82
|
+
identifier: scheme.identifier
|
|
83
|
+
});
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
_toJskosConcept(skosmosConcept, { concept, scheme, result, language } = {}) {
|
|
88
|
+
if (!skosmosConcept) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
concept = jskos.deepCopy(concept || {});
|
|
92
|
+
language = language || skosmosConcept.lang || "en";
|
|
93
|
+
concept.uri = skosmosConcept.uri;
|
|
94
|
+
if (scheme) {
|
|
95
|
+
concept.inScheme = [scheme];
|
|
96
|
+
}
|
|
97
|
+
let prefLabel = skosmosConcept.matchedPrefLabel || skosmosConcept.prefLabel || skosmosConcept.label;
|
|
98
|
+
if (_.isString(prefLabel)) {
|
|
99
|
+
_.set(concept, `prefLabel.${language}`, prefLabel);
|
|
100
|
+
} else {
|
|
101
|
+
if (prefLabel && !_.isArray(prefLabel)) {
|
|
102
|
+
prefLabel = [prefLabel];
|
|
103
|
+
}
|
|
104
|
+
for (let label of prefLabel || []) {
|
|
105
|
+
_.set(concept, `prefLabel.${label.lang}`, label.value);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
let altLabel = skosmosConcept.altLabel;
|
|
109
|
+
if (_.isString(altLabel)) {
|
|
110
|
+
_.set(concept, `altLabel.${language}`, [altLabel]);
|
|
111
|
+
} else {
|
|
112
|
+
if (altLabel && !_.isArray(altLabel)) {
|
|
113
|
+
altLabel = [altLabel];
|
|
114
|
+
}
|
|
115
|
+
for (let label of altLabel || []) {
|
|
116
|
+
if (_.get(concept, `altLabel.${label.lang}`)) {
|
|
117
|
+
concept.altLabel[label.lang].push(label.value);
|
|
118
|
+
concept.altLabel[label.lang] = _.uniq(concept.altLabel[label.lang]);
|
|
119
|
+
} else {
|
|
120
|
+
_.set(concept, `altLabel.${label.lang}`, [label.value]);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const notation = skosmosConcept.notation || skosmosConcept["skos:notation"] || jskos.notation(concept);
|
|
125
|
+
if (notation) {
|
|
126
|
+
concept.notation = [notation.value || notation];
|
|
127
|
+
}
|
|
128
|
+
if (skosmosConcept.broader) {
|
|
129
|
+
if (!_.isArray(skosmosConcept.broader)) {
|
|
130
|
+
skosmosConcept.broader = [skosmosConcept.broader];
|
|
131
|
+
}
|
|
132
|
+
concept.broader = skosmosConcept.broader.map((concept2) => _.isString(concept2) ? { uri: concept2 } : concept2);
|
|
133
|
+
}
|
|
134
|
+
if (skosmosConcept.hasChildren === true) {
|
|
135
|
+
concept.narrower = [null];
|
|
136
|
+
} else if (skosmosConcept.hasChildren === false) {
|
|
137
|
+
concept.narrower = [];
|
|
138
|
+
}
|
|
139
|
+
if (skosmosConcept.type && !_.isArray(skosmosConcept.type)) {
|
|
140
|
+
skosmosConcept.type = [skosmosConcept.type];
|
|
141
|
+
}
|
|
142
|
+
concept.type = concept.type || [];
|
|
143
|
+
for (let type of skosmosConcept.type || []) {
|
|
144
|
+
if (!jskos.isValidUri(type)) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const uriScheme = type.slice(0, type.indexOf(":"));
|
|
148
|
+
if (result && result["@context"] && result["@context"][uriScheme]) {
|
|
149
|
+
type = type.replace(uriScheme + ":", result["@context"][uriScheme]);
|
|
150
|
+
}
|
|
151
|
+
concept.type.push(type);
|
|
152
|
+
}
|
|
153
|
+
concept.type = _.uniq(concept.type);
|
|
154
|
+
if (!concept.type.length) {
|
|
155
|
+
concept.type = ["http://www.w3.org/2004/02/skos/core#Concept"];
|
|
156
|
+
}
|
|
157
|
+
return concept;
|
|
158
|
+
}
|
|
159
|
+
async getSchemes({ ...config }) {
|
|
160
|
+
const schemes = [];
|
|
161
|
+
for (let scheme of this.schemes || []) {
|
|
162
|
+
const url = this._getApiUrl(scheme, "/");
|
|
163
|
+
const data = await this.axios({
|
|
164
|
+
...config,
|
|
165
|
+
method: "get",
|
|
166
|
+
url
|
|
167
|
+
});
|
|
168
|
+
const resultScheme = data.conceptschemes.find((s) => jskos.compare(s, scheme));
|
|
169
|
+
const label = resultScheme && (resultScheme.prefLabel || resultScheme.label || resultScheme.title);
|
|
170
|
+
if (label) {
|
|
171
|
+
_.set(scheme, `prefLabel.${this._language}`, label);
|
|
172
|
+
}
|
|
173
|
+
schemes.push(scheme);
|
|
174
|
+
this._approvedSchemes = this._approvedSchemes || [];
|
|
175
|
+
if (!this._approvedSchemes.find((s) => jskos.compare(scheme, s))) {
|
|
176
|
+
this._approvedSchemes.push({
|
|
177
|
+
uri: resultScheme.uri,
|
|
178
|
+
identifier: jskos.getAllUris(scheme)
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return schemes;
|
|
183
|
+
}
|
|
184
|
+
async getTop({ scheme, ...config }) {
|
|
185
|
+
const url = this._getApiUrl(scheme, "/topConcepts");
|
|
186
|
+
const schemeUri = await this._getSchemeUri(scheme);
|
|
187
|
+
if (!schemeUri) {
|
|
188
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: "scheme", message: "Missing or unsupported scheme or VOCID property on scheme" });
|
|
189
|
+
}
|
|
190
|
+
_.set(config, "params.scheme", schemeUri);
|
|
191
|
+
const response = await this.axios({
|
|
192
|
+
...config,
|
|
193
|
+
method: "get",
|
|
194
|
+
url
|
|
195
|
+
});
|
|
196
|
+
const concepts = [];
|
|
197
|
+
for (let concept of response.topconcepts || []) {
|
|
198
|
+
const newConcept = this._toJskosConcept(concept, {
|
|
199
|
+
scheme,
|
|
200
|
+
language: this._language
|
|
201
|
+
});
|
|
202
|
+
newConcept.topConceptOf = [scheme];
|
|
203
|
+
concepts.push(newConcept);
|
|
204
|
+
}
|
|
205
|
+
return concepts;
|
|
206
|
+
}
|
|
207
|
+
async getConcepts({ concepts, ...config }) {
|
|
208
|
+
if (!_.isArray(concepts)) {
|
|
209
|
+
concepts = [concepts];
|
|
210
|
+
}
|
|
211
|
+
concepts = concepts.map((c) => ({ uri: c.uri, inScheme: c.inScheme }));
|
|
212
|
+
const newConcepts = [];
|
|
213
|
+
for (let concept of concepts) {
|
|
214
|
+
const url = this._getDataUrl(concept, { addFormatParameter: false });
|
|
215
|
+
if (!url) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
const result = await this.axios({
|
|
219
|
+
...config,
|
|
220
|
+
method: "get",
|
|
221
|
+
url,
|
|
222
|
+
params: {
|
|
223
|
+
uri: concept.uri,
|
|
224
|
+
format: "application/json"
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
const resultConcept = result && result.graph && result.graph.find((c) => jskos.compare(c, concept));
|
|
228
|
+
if (resultConcept) {
|
|
229
|
+
const newConcept = this._toJskosConcept(resultConcept, { concept, result });
|
|
230
|
+
for (let type of ["broader", "narrower"]) {
|
|
231
|
+
let relatives = resultConcept[type] || newConcept[type];
|
|
232
|
+
if (relatives && !_.isArray(relatives)) {
|
|
233
|
+
relatives = [relatives];
|
|
234
|
+
}
|
|
235
|
+
if (!relatives) {
|
|
236
|
+
relatives = [];
|
|
237
|
+
}
|
|
238
|
+
newConcept[type] = relatives.map((r) => this._toJskosConcept(result.graph.find((c) => jskos.compare(c, r)), { scheme: concept.inScheme[0], result }));
|
|
239
|
+
}
|
|
240
|
+
newConcept.ancestors = [];
|
|
241
|
+
newConcepts.push(newConcept);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return newConcepts;
|
|
245
|
+
}
|
|
246
|
+
async getNarrower({ concept, ...config }) {
|
|
247
|
+
if (!concept || !concept.uri) {
|
|
248
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: "concept" });
|
|
249
|
+
}
|
|
250
|
+
const scheme = concept.inScheme[0];
|
|
251
|
+
const url = this._getApiUrl(scheme, "/children");
|
|
252
|
+
_.set(config, "params.uri", concept.uri);
|
|
253
|
+
const response = await this.axios({
|
|
254
|
+
...config,
|
|
255
|
+
method: "get",
|
|
256
|
+
url
|
|
257
|
+
});
|
|
258
|
+
const concepts = (response.narrower || []).map((c) => this._toJskosConcept(c, { scheme }));
|
|
259
|
+
return concepts;
|
|
260
|
+
}
|
|
261
|
+
async getAncestors({ concept, ...config }) {
|
|
262
|
+
if (!concept || !concept.uri) {
|
|
263
|
+
throw new errors.InvalidOrMissingParameterError({ parameter: "concept" });
|
|
264
|
+
}
|
|
265
|
+
const scheme = concept.inScheme[0];
|
|
266
|
+
const url = this._getApiUrl(scheme, "/broaderTransitive");
|
|
267
|
+
_.set(config, "params.uri", concept.uri);
|
|
268
|
+
const response = await this.axios({
|
|
269
|
+
...config,
|
|
270
|
+
method: "get",
|
|
271
|
+
url
|
|
272
|
+
});
|
|
273
|
+
let ancestors = [];
|
|
274
|
+
let uri = concept.uri;
|
|
275
|
+
while (uri) {
|
|
276
|
+
if (uri != concept.uri) {
|
|
277
|
+
const ancestor = _.get(response, `broaderTransitive["${uri}"]`);
|
|
278
|
+
ancestors = [ancestor].concat(ancestors);
|
|
279
|
+
}
|
|
280
|
+
uri = _.get(response, `broaderTransitive["${uri}"].broader[0]`);
|
|
281
|
+
}
|
|
282
|
+
const concepts = ancestors.map((c) => this._toJskosConcept(c, { scheme })).filter((c) => c.uri != concept.uri);
|
|
283
|
+
return concepts;
|
|
284
|
+
}
|
|
285
|
+
async suggest(config) {
|
|
286
|
+
config._raw = true;
|
|
287
|
+
const concepts = await this.search(config);
|
|
288
|
+
const result = [config.search, [], [], []];
|
|
289
|
+
for (let concept of concepts) {
|
|
290
|
+
const notation = jskos.notation(concept);
|
|
291
|
+
const label = jskos.prefLabel(concept);
|
|
292
|
+
result[1].push((notation ? notation + " " : "") + label);
|
|
293
|
+
result[2].push("");
|
|
294
|
+
result[3].push(concept.uri);
|
|
295
|
+
}
|
|
296
|
+
if (concepts._totalCount != void 0) {
|
|
297
|
+
result._totalCount = concepts._totalCount;
|
|
298
|
+
} else {
|
|
299
|
+
result._totalCount = concepts.length;
|
|
300
|
+
}
|
|
301
|
+
return result;
|
|
302
|
+
}
|
|
303
|
+
async search({ search, scheme, limit, types = [], ...config }) {
|
|
304
|
+
const url = this._getApiUrl(scheme, "/search");
|
|
305
|
+
_.set(config, "params.query", `${search}*`);
|
|
306
|
+
_.set(config, "params.unique", 1);
|
|
307
|
+
_.set(config, "params.maxhits", limit || 100);
|
|
308
|
+
_.set(config, "params.type", types.join(" "));
|
|
309
|
+
const response = await this.axios({
|
|
310
|
+
...config,
|
|
311
|
+
method: "get",
|
|
312
|
+
url
|
|
313
|
+
});
|
|
314
|
+
const concepts = (response.results || []).map((c) => this._toJskosConcept(c, { scheme }));
|
|
315
|
+
return concepts;
|
|
316
|
+
}
|
|
317
|
+
async getTypes({ scheme, ...config }) {
|
|
318
|
+
const url = this._getApiUrl(scheme, "/types");
|
|
319
|
+
const types = [];
|
|
320
|
+
const response = await this.axios({
|
|
321
|
+
...config,
|
|
322
|
+
method: "get",
|
|
323
|
+
url
|
|
324
|
+
});
|
|
325
|
+
for (let type of response && response.types || []) {
|
|
326
|
+
if (type.uri == "http://www.w3.org/2004/02/skos/core#Concept") {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if (type.label) {
|
|
330
|
+
type.prefLabel = {
|
|
331
|
+
[response["@context"]["@language"]]: type.label
|
|
332
|
+
};
|
|
333
|
+
delete type.label;
|
|
334
|
+
}
|
|
335
|
+
types.push(type);
|
|
336
|
+
}
|
|
337
|
+
types._url = url;
|
|
338
|
+
return types;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
SkosmosApiProvider.providerName = "SkosmosApi";
|
|
342
|
+
SkosmosApiProvider.providerType = "http://bartoc.org/api-type/skosmos";
|
|
343
|
+
export {
|
|
344
|
+
SkosmosApiProvider as default
|
|
345
|
+
};
|