cocoda-sdk 3.2.3 → 3.3.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/dist/esm/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import CocodaSDK from "./lib/CocodaSDK.js";
2
2
  import * as errors from "./errors/index.js";
3
+ import * as utils from "./utils/index.js";
3
4
  export * from "./providers/index.js";
4
5
  const cdk = new CocodaSDK();
5
6
  import * as providers from "./providers/index.js";
@@ -10,5 +11,6 @@ export {
10
11
  CocodaSDK,
11
12
  addAllProviders,
12
13
  cdk,
13
- errors
14
+ errors,
15
+ utils
14
16
  };
@@ -298,7 +298,7 @@ class BaseProvider {
298
298
  return (await this.getConcepts({ ...config, concepts: [concept] }))[0];
299
299
  };
300
300
  for (let type of ["broader", "narrower", "ancestors"]) {
301
- if (Array.isArray(concept[type]) && !concept[type].includes(null)) {
301
+ if (Array.isArray(concept[type]) && concept[type].length && !concept[type].includes(null)) {
302
302
  concept[type] = this.adjustConcepts(concept[type]);
303
303
  }
304
304
  }
@@ -8,6 +8,7 @@ import LabelSearchSuggestionProvider from "./label-search-suggestion-provider.js
8
8
  import SkosmosApiProvider from "./skosmos-api-provider.js";
9
9
  import LocApiProvider from "./loc-api-provider.js";
10
10
  import SkohubProvider from "./skohub-provider.js";
11
+ import MyCoReProvider from "./mycore-provider.js";
11
12
  export {
12
13
  BaseProvider,
13
14
  ConceptApiProvider,
@@ -15,6 +16,7 @@ export {
15
16
  LocApiProvider,
16
17
  LocalMappingsProvider,
17
18
  MappingsApiProvider,
19
+ MyCoReProvider,
18
20
  OccurrencesApiProvider,
19
21
  ReconciliationApiProvider,
20
22
  SkohubProvider,
@@ -0,0 +1,216 @@
1
+ import BaseProvider from "./base-provider.js";
2
+ import * as _ from "../utils/lodash.js";
3
+ import * as errors from "../errors/index.js";
4
+ import { listOfCapabilities } from "../utils/index.js";
5
+ import jskos from "jskos-tools";
6
+ import FlexSearch from "flexsearch";
7
+ const data = {};
8
+ class MyCoReProvider extends BaseProvider {
9
+ _prepare() {
10
+ this.has.schemes = true;
11
+ this.has.top = true;
12
+ this.has.data = true;
13
+ this.has.concepts = true;
14
+ this.has.narrower = true;
15
+ this.has.ancestors = true;
16
+ this.has.suggest = true;
17
+ this.has.search = true;
18
+ listOfCapabilities.filter((c) => !this.has[c]).forEach((c) => {
19
+ this.has[c] = false;
20
+ });
21
+ }
22
+ _setup() {
23
+ this._scheme = null;
24
+ }
25
+ static _registryConfigForBartocApiConfig({ url, scheme } = {}) {
26
+ if (!url || !scheme) {
27
+ return null;
28
+ }
29
+ return {
30
+ api: url
31
+ };
32
+ }
33
+ _schemeInfoToJSKOS(schemeInfo) {
34
+ const uri = schemeInfo.labels.find((l) => l.lang === "x-uri").text;
35
+ const prefLabel = {};
36
+ schemeInfo.labels.filter((l) => !l.lang.startsWith("x-")).forEach((l) => {
37
+ prefLabel[l.lang] = l.text;
38
+ });
39
+ const scheme = {
40
+ uri,
41
+ prefLabel
42
+ };
43
+ if (schemeInfo.categories && schemeInfo.categories.length) {
44
+ scheme.topConcepts = [null];
45
+ }
46
+ if (schemeInfo.category && schemeInfo.category.length) {
47
+ scheme.concepts = [null];
48
+ }
49
+ return scheme;
50
+ }
51
+ _categoryToJSKOS(category, { scheme, broader = [] }) {
52
+ if (!category || !scheme) {
53
+ return null;
54
+ }
55
+ const id = category.ID;
56
+ const uri = `${scheme.uri}/${id}`;
57
+ if (data[scheme.uri].concepts[uri]) {
58
+ return data[scheme.uri].concepts[uri];
59
+ }
60
+ const prefLabel = {};
61
+ category.labels.filter((l) => !l.lang.startsWith("x-") && l.text).forEach((l) => {
62
+ prefLabel[l.lang] = l.text.replace(`${id} `, "");
63
+ data[scheme.uri].searchIndex.add(uri, prefLabel[l.lang]);
64
+ });
65
+ const scopeNote = {};
66
+ category.labels.filter((l) => !l.lang.startsWith("x-") && l.description).forEach((l) => {
67
+ if (!scopeNote[l.lang]) {
68
+ scopeNote[l.lang] = [];
69
+ }
70
+ scopeNote[l.lang].push(l.description);
71
+ });
72
+ data[scheme.uri].concepts[uri] = {
73
+ uri,
74
+ notation: [id],
75
+ prefLabel,
76
+ scopeNote,
77
+ inScheme: [{ uri: scheme.uri }],
78
+ narrower: (category.categories || []).map((c) => ({ uri: `${scheme.uri}/${c.ID}` })),
79
+ broader
80
+ };
81
+ return data[scheme.uri].concepts[uri];
82
+ }
83
+ _removeNarrower(concept) {
84
+ if (!concept)
85
+ return concept;
86
+ return Object.assign({}, concept, { narrower: concept.narrower && concept.narrower.length ? [null] : [] });
87
+ }
88
+ async _loadSchemeData(config) {
89
+ const schemeInfo = await this.axios({
90
+ ...config,
91
+ method: "get",
92
+ url: this._api.api,
93
+ _skipAdditionalParameters: true
94
+ });
95
+ this._scheme = this._schemeInfoToJSKOS(schemeInfo);
96
+ const uri = this._scheme.uri;
97
+ data[uri] = {
98
+ schemeInfo,
99
+ searchIndex: FlexSearch.create({
100
+ tokenize: "full"
101
+ }),
102
+ concepts: {}
103
+ };
104
+ const dealWithCategory = (category, { broader = [] } = {}) => {
105
+ const concept = this._categoryToJSKOS(category, { scheme: this._scheme, broader });
106
+ (category.categories || []).forEach((c) => dealWithCategory(c, { broader: [{ uri: concept.uri }] }));
107
+ };
108
+ schemeInfo.categories.forEach((category) => dealWithCategory(category));
109
+ data[uri].topConcepts = schemeInfo.categories.map((category) => this._categoryToJSKOS(category, { scheme: this._scheme }));
110
+ }
111
+ async getSchemes(config = {}) {
112
+ if (!this._api.api) {
113
+ throw new errors.MissingApiUrlError();
114
+ }
115
+ if (!this._scheme) {
116
+ if (!this._loadSchemeDataPromise) {
117
+ this._loadSchemeDataPromise = this._loadSchemeData(config);
118
+ }
119
+ await this._loadSchemeDataPromise;
120
+ }
121
+ return [this._scheme];
122
+ }
123
+ async getTop({ scheme, ...config }) {
124
+ if (!scheme || !scheme.uri) {
125
+ throw new errors.InvalidOrMissingParameterError({ parameter: "scheme", message: "Missing scheme URI" });
126
+ }
127
+ if (!this._scheme) {
128
+ await this.getSchemes(config);
129
+ }
130
+ if (!jskos.compare(scheme, this._scheme)) {
131
+ throw new errors.InvalidOrMissingParameterError({ parameter: "scheme", message: "Requested vocabulary seems to be unsupported by this API." });
132
+ }
133
+ return data[this._scheme.uri].topConcepts.map(this._removeNarrower);
134
+ }
135
+ async getConcepts({ concepts, ...config }) {
136
+ if (!_.isArray(concepts)) {
137
+ concepts = [concepts];
138
+ }
139
+ if (!this._scheme) {
140
+ await this.getSchemes(config);
141
+ }
142
+ return concepts.map((c) => data[this._scheme.uri].concepts[c.uri]).map(this._removeNarrower);
143
+ }
144
+ async getAncestors({ concept, ...config }) {
145
+ if (!concept || !concept.uri) {
146
+ throw new errors.InvalidOrMissingParameterError({ parameter: "concept" });
147
+ }
148
+ if (concept.ancestors && concept.ancestors[0] !== null) {
149
+ return concept.ancestors;
150
+ }
151
+ if (!this._scheme) {
152
+ await this.getSchemes(config);
153
+ }
154
+ concept = data[this._scheme.uri].concepts[concept.uri];
155
+ const broader = concept && concept.broader && concept.broader[0];
156
+ if (!broader) {
157
+ return [];
158
+ }
159
+ return [broader].concat(await this.getAncestors({ concept: broader, ...config }));
160
+ }
161
+ async getNarrower({ concept, ...config }) {
162
+ if (!concept || !concept.uri) {
163
+ throw new errors.InvalidOrMissingParameterError({ parameter: "concept" });
164
+ }
165
+ if (concept.narrower && concept.narrower[0] !== null) {
166
+ return concept.narrower;
167
+ }
168
+ if (!this._scheme) {
169
+ await this.getSchemes(config);
170
+ }
171
+ concept = data[this._scheme.uri].concepts[concept.uri];
172
+ return (concept && concept.narrower || []).map((c) => data[this._scheme.uri].concepts[c.uri]).map(this._removeNarrower);
173
+ }
174
+ async search({ search, scheme, limit = 100 }) {
175
+ if (!scheme || !scheme.uri) {
176
+ throw new errors.InvalidOrMissingParameterError({ parameter: "scheme" });
177
+ }
178
+ if (!search) {
179
+ throw new errors.InvalidOrMissingParameterError({ parameter: "search" });
180
+ }
181
+ if (!scheme || !scheme.uri) {
182
+ throw new errors.InvalidOrMissingParameterError({ parameter: "scheme", message: "Missing scheme URI" });
183
+ }
184
+ if (!this._scheme) {
185
+ await this.getSchemes();
186
+ }
187
+ if (!jskos.compare(scheme, this._scheme)) {
188
+ throw new errors.InvalidOrMissingParameterError({ parameter: "scheme", message: "Requested vocabulary seems to be unsupported by this API." });
189
+ }
190
+ const result = await data[this._scheme.uri].searchIndex.search(search);
191
+ return result.map((uri) => data[this._scheme.uri].concepts[uri]).map(this._removeNarrower).slice(0, limit);
192
+ }
193
+ async suggest(config) {
194
+ config._raw = true;
195
+ const concepts = await this.search(config);
196
+ const result = [config.search, [], [], []];
197
+ for (let concept of concepts) {
198
+ const notation = jskos.notation(concept);
199
+ const label = jskos.prefLabel(concept);
200
+ result[1].push((notation ? notation + " " : "") + label);
201
+ result[2].push("");
202
+ result[3].push(concept.uri);
203
+ }
204
+ if (concepts._totalCount != void 0) {
205
+ result._totalCount = concepts._totalCount;
206
+ } else {
207
+ result._totalCount = concepts.length;
208
+ }
209
+ return result;
210
+ }
211
+ }
212
+ MyCoReProvider.providerName = "MyCoRe";
213
+ MyCoReProvider.providerType = "http://bartoc.org/api-type/mycore";
214
+ export {
215
+ MyCoReProvider as default
216
+ };
@@ -3,9 +3,13 @@ import jskos from "jskos-tools";
3
3
  import * as _ from "../utils/lodash.js";
4
4
  import * as errors from "../errors/index.js";
5
5
  import * as utils from "../utils/index.js";
6
+ const cache = {};
6
7
  class OccurrencesApiProvider extends BaseProvider {
8
+ get _cache() {
9
+ return cache[this.uri];
10
+ }
7
11
  _prepare() {
8
- this._cache = [];
12
+ cache[this.uri] = [];
9
13
  this._occurrencesSupportedSchemes = [];
10
14
  this.has.occurrences = true;
11
15
  this.has.mappings = true;
@@ -146,7 +150,7 @@ class OccurrencesApiProvider extends BaseProvider {
146
150
  data
147
151
  });
148
152
  if (this._cache.length > 20) {
149
- this._cache = this._cache.slice(this._cache.length - 20);
153
+ cache[this.uri] = this._cache.slice(this._cache.length - 20);
150
154
  }
151
155
  return data;
152
156
  }
@@ -3,9 +3,13 @@ import jskos from "jskos-tools";
3
3
  import * as _ from "../utils/lodash.js";
4
4
  import * as errors from "../errors/index.js";
5
5
  import { listOfCapabilities } from "../utils/index.js";
6
+ const cache = {};
6
7
  class ReconciliationApiProvider extends BaseProvider {
8
+ get _cache() {
9
+ return cache[this.uri];
10
+ }
7
11
  _prepare() {
8
- this._cache = [];
12
+ cache[this.uri] = [];
9
13
  this.has.mappings = true;
10
14
  listOfCapabilities.filter((c) => !this.has[c]).forEach((c) => {
11
15
  this.has[c] = false;
@@ -132,7 +136,7 @@ class ReconciliationApiProvider extends BaseProvider {
132
136
  };
133
137
  this._cache.push(newCacheEntry);
134
138
  if (this._cache.length > 20) {
135
- this._cache = this._cache.slice(this._cache.length - 20);
139
+ cache[this.uri] = this._cache.slice(this._cache.length - 20);
136
140
  }
137
141
  return newCacheEntry;
138
142
  }
@@ -12,6 +12,7 @@ function decodeUnicode(text) {
12
12
  }
13
13
  );
14
14
  }
15
+ const data = {};
15
16
  class SkohubProvider extends BaseProvider {
16
17
  _prepare() {
17
18
  this.has.schemes = true;
@@ -25,11 +26,20 @@ class SkohubProvider extends BaseProvider {
25
26
  listOfCapabilities.filter((c) => !this.has[c]).forEach((c) => {
26
27
  this.has[c] = false;
27
28
  });
29
+ data[this.uri] = {
30
+ index: {},
31
+ conceptCache: {},
32
+ schemeCache: {}
33
+ };
28
34
  }
29
- _setup() {
30
- this._index = {};
31
- this._conceptCache = {};
32
- this._schemeCache = {};
35
+ get _index() {
36
+ return data[this.uri] && data[this.uri].index;
37
+ }
38
+ get _conceptCache() {
39
+ return data[this.uri] && data[this.uri].conceptCache;
40
+ }
41
+ get _schemeCache() {
42
+ return data[this.uri] && data[this.uri].schemeCache;
33
43
  }
34
44
  static _registryConfigForBartocApiConfig({ url, scheme } = {}) {
35
45
  if (!url || !scheme) {
@@ -55,11 +65,11 @@ class SkohubProvider extends BaseProvider {
55
65
  if (uri.endsWith("/")) {
56
66
  postfix = "index.json";
57
67
  }
58
- const data = await this.axios({ ...config, url: `${uri}${postfix}`, _skipAdditionalParameters: true });
59
- if (data.id !== uri) {
68
+ const data2 = await this.axios({ ...config, url: `${uri}${postfix}`, _skipAdditionalParameters: true });
69
+ if (data2.id !== uri) {
60
70
  throw new errors.InvalidRequestError({ message: "Skohub URL did not return expected concept scheme" });
61
71
  }
62
- const { title, preferredNamespaceUri, hasTopConcept, description } = data;
72
+ const { title, preferredNamespaceUri, hasTopConcept, description } = data2;
63
73
  scheme = { uri, identifier: uris.filter((u) => u !== uri) };
64
74
  scheme.prefLabel = title;
65
75
  Object.keys(scheme.prefLabel || {}).forEach((key) => {
@@ -87,33 +97,33 @@ class SkohubProvider extends BaseProvider {
87
97
  return this._conceptCache[uri];
88
98
  }
89
99
  try {
90
- const data = await this.axios({ ...config, url: `${uri}.json`, _skipAdditionalParameters: true });
91
- if (data.id !== uri) {
100
+ const data2 = await this.axios({ ...config, url: `${uri}.json`, _skipAdditionalParameters: true });
101
+ if (data2.id !== uri) {
92
102
  throw new errors.InvalidRequestError({ message: "Skohub URL did not return expected concept URI" });
93
103
  }
94
- const concept = this._toJskosConcept(data);
104
+ const concept = this._toJskosConcept(data2);
95
105
  this._conceptCache[uri] = concept;
96
106
  return concept;
97
107
  } catch (error) {
98
108
  return null;
99
109
  }
100
110
  }
101
- _toJskosConcept(data) {
102
- const concept = { uri: data.id };
103
- concept.prefLabel = data.prefLabel;
111
+ _toJskosConcept(data2) {
112
+ const concept = { uri: data2.id };
113
+ concept.prefLabel = data2.prefLabel;
104
114
  Object.keys(concept.prefLabel || {}).forEach((key) => {
105
115
  concept.prefLabel[key] = decodeUnicode(concept.prefLabel[key]);
106
116
  });
107
- concept.narrower = (data.narrower || []).map((c) => this._toJskosConcept(c));
108
- concept.notation = data.notation || [];
109
- if (data.broader && data.broader.id) {
110
- concept.broader = [{ uri: data.broader.id }];
117
+ concept.narrower = (data2.narrower || []).map((c) => this._toJskosConcept(c));
118
+ concept.notation = data2.notation || [];
119
+ if (data2.broader && data2.broader.id) {
120
+ concept.broader = [{ uri: data2.broader.id }];
111
121
  }
112
- if (data.inScheme && data.inScheme.id) {
113
- concept.inScheme = [{ uri: data.inScheme.id }];
122
+ if (data2.inScheme && data2.inScheme.id) {
123
+ concept.inScheme = [{ uri: data2.inScheme.id }];
114
124
  }
115
- if (data.scopeNote) {
116
- concept.scopeNote = data.scopeNote;
125
+ if (data2.scopeNote) {
126
+ concept.scopeNote = data2.scopeNote;
117
127
  Object.keys(concept.scopeNote).forEach((key) => {
118
128
  concept.scopeNote[key] = [decodeUnicode(concept.scopeNote[key])];
119
129
  });
@@ -185,13 +195,13 @@ class SkohubProvider extends BaseProvider {
185
195
  if (scheme.uri.endsWith("/")) {
186
196
  postfix = `index${postfix}`;
187
197
  }
188
- const data = await this.axios({ url: `${scheme.uri}${postfix}`, _skipAdditionalParameters: true });
189
- if (data.length < 100) {
198
+ const data2 = await this.axios({ url: `${scheme.uri}${postfix}`, _skipAdditionalParameters: true });
199
+ if (data2.length < 100) {
190
200
  this._index[scheme.uri][lang] = null;
191
201
  continue;
192
202
  }
193
203
  index = FlexSearch.create();
194
- index.import(data);
204
+ index.import(data2);
195
205
  this._index[scheme.uri][lang] = index;
196
206
  break;
197
207
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cocoda-sdk",
3
- "version": "3.2.3",
3
+ "version": "3.3.0",
4
4
  "description": "SDK for Cocoda",
5
5
  "main": "dist/cjs/index.cjs",
6
6
  "module": "dist/esm/index.js",
@@ -27,7 +27,7 @@
27
27
  "release:patch": "SEMVER=patch npm run release",
28
28
  "release:minor": "SEMVER=minor npm run release",
29
29
  "release:major": "SEMVER=major npm run release",
30
- "postinstall": "[ -d './dist' ] || npm run build"
30
+ "prepare": "[ -d './dist' ] || npm run build"
31
31
  },
32
32
  "lint-staged": {
33
33
  "**/*.js": [