@faubulous/mentor-rdf 2.1.0 → 2.1.2
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 +56 -0
- package/dist/index.js +557 -38
- package/dist/index.js.map +3 -3
- package/dist/rdf/concept-repository.d.ts +228 -5
- package/dist/rdf/resource-repository.d.ts +5 -0
- package/dist/rdf/store.d.ts +7 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2948,24 +2948,288 @@ var ConceptRepository = class extends ResourceRepository {
|
|
|
2948
2948
|
/**
|
|
2949
2949
|
* Get all collections.
|
|
2950
2950
|
* @param graphUris URI of the graphs to search for collections.
|
|
2951
|
+
* @param options Optional query parameters.
|
|
2951
2952
|
* @returns An iterator of URIs of all collections.
|
|
2952
2953
|
*/
|
|
2953
|
-
*getCollections(graphUris) {
|
|
2954
|
+
*getCollections(graphUris, options) {
|
|
2954
2955
|
const yielded = /* @__PURE__ */ new Set();
|
|
2955
2956
|
for (let q of this.store.matchAll(graphUris, null, rdf.type, skos.Collection)) {
|
|
2956
2957
|
const s = q.subject;
|
|
2957
|
-
if (!yielded.has(s.value)) {
|
|
2958
|
+
if (!yielded.has(s.value) && !this._skipCollection(graphUris, s, options)) {
|
|
2958
2959
|
yielded.add(s.value);
|
|
2959
2960
|
yield s.value;
|
|
2960
2961
|
}
|
|
2961
2962
|
}
|
|
2962
2963
|
for (let q of this.store.matchAll(graphUris, null, rdf.type, skos.OrderedCollection)) {
|
|
2964
|
+
const s = q.subject;
|
|
2965
|
+
if (!yielded.has(s.value) && !this._skipCollection(graphUris, s, options)) {
|
|
2966
|
+
yielded.add(s.value);
|
|
2967
|
+
yield s.value;
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
/**
|
|
2972
|
+
* Indicate if a collection should be excluded from a query result.
|
|
2973
|
+
*
|
|
2974
|
+
* Note: In contrast to other resource types, blank nodes and referenced collections are
|
|
2975
|
+
* included by default so that the result is unchanged when no options are provided.
|
|
2976
|
+
* @param graphUris URI of the graphs to search for collections.
|
|
2977
|
+
* @param subject The collection to test.
|
|
2978
|
+
* @param options Optional query parameters.
|
|
2979
|
+
* @returns `true` if the collection should be excluded, `false` otherwise.
|
|
2980
|
+
*/
|
|
2981
|
+
_skipCollection(graphUris, subject, options) {
|
|
2982
|
+
if (this.skip(graphUris, subject, options, { includeBlankNodes: true, includeReferenced: true })) {
|
|
2983
|
+
return true;
|
|
2984
|
+
}
|
|
2985
|
+
if (options?.inScheme === void 0) {
|
|
2986
|
+
return false;
|
|
2987
|
+
}
|
|
2988
|
+
if (options.inScheme === null) {
|
|
2989
|
+
return this.hasConceptScheme(graphUris, subject.value);
|
|
2990
|
+
}
|
|
2991
|
+
return !this.isInScheme(graphUris, subject.value, options.inScheme);
|
|
2992
|
+
}
|
|
2993
|
+
/**
|
|
2994
|
+
* Indicate if a resource is associated with any concept scheme via `skos:inScheme`.
|
|
2995
|
+
* @param graphUris URIs of the graphs to search for concepts.
|
|
2996
|
+
* @param subjectUri URI of a resource.
|
|
2997
|
+
* @returns `true` if the resource is in a concept scheme, `false` otherwise.
|
|
2998
|
+
*/
|
|
2999
|
+
hasConceptScheme(graphUris, subjectUri) {
|
|
3000
|
+
const s = dataFactory.namedNode(subjectUri);
|
|
3001
|
+
for (let _ of this.store.matchAll(graphUris, s, skos.inScheme, null)) {
|
|
3002
|
+
return true;
|
|
3003
|
+
}
|
|
3004
|
+
return false;
|
|
3005
|
+
}
|
|
3006
|
+
/**
|
|
3007
|
+
* Indicate if a resource is associated with a given concept scheme via `skos:inScheme`.
|
|
3008
|
+
* @param graphUris URIs of the graphs to search for concepts.
|
|
3009
|
+
* @param subjectUri URI of a resource.
|
|
3010
|
+
* @param schemeUri URI of a concept scheme.
|
|
3011
|
+
* @returns `true` if the resource is in the given concept scheme, `false` otherwise.
|
|
3012
|
+
*/
|
|
3013
|
+
isInScheme(graphUris, subjectUri, schemeUri) {
|
|
3014
|
+
const s = dataFactory.namedNode(subjectUri);
|
|
3015
|
+
const o = dataFactory.namedNode(schemeUri);
|
|
3016
|
+
for (let _ of this.store.matchAll(graphUris, s, skos.inScheme, o)) {
|
|
3017
|
+
return true;
|
|
3018
|
+
}
|
|
3019
|
+
return false;
|
|
3020
|
+
}
|
|
3021
|
+
/**
|
|
3022
|
+
* Indicate if a concept is explicitly associated with a given concept scheme, either via
|
|
3023
|
+
* `skos:inScheme` or via `skos:topConceptOf`.
|
|
3024
|
+
*
|
|
3025
|
+
* Note: The `skos:broader` and `skos:narrower` relations are *not* taken into account, because
|
|
3026
|
+
* they may cross the boundaries of a concept scheme. Use {@link getAllConceptsInScheme} to get
|
|
3027
|
+
* the concepts that are displayed below a concept scheme.
|
|
3028
|
+
* @param graphUris URIs of the graphs to search for concepts.
|
|
3029
|
+
* @param subjectUri URI of a concept.
|
|
3030
|
+
* @param schemeUri URI of a concept scheme.
|
|
3031
|
+
* @returns `true` if the concept is associated with the concept scheme, `false` otherwise.
|
|
3032
|
+
*/
|
|
3033
|
+
isConceptOfScheme(graphUris, subjectUri, schemeUri) {
|
|
3034
|
+
if (this.isInScheme(graphUris, subjectUri, schemeUri)) {
|
|
3035
|
+
return true;
|
|
3036
|
+
}
|
|
3037
|
+
const s = dataFactory.namedNode(subjectUri);
|
|
3038
|
+
const o = dataFactory.namedNode(schemeUri);
|
|
3039
|
+
for (let _ of this.store.matchAll(graphUris, s, skos.topConceptOf, o)) {
|
|
3040
|
+
return true;
|
|
3041
|
+
}
|
|
3042
|
+
return false;
|
|
3043
|
+
}
|
|
3044
|
+
/**
|
|
3045
|
+
* Indicate if a concept can be displayed below a given concept scheme.
|
|
3046
|
+
*
|
|
3047
|
+
* Concepts that are not associated with any concept scheme belong to every concept scheme they
|
|
3048
|
+
* can be reached from, so that they are not hidden in vocabularies that only annotate their top
|
|
3049
|
+
* concepts with `skos:inScheme`.
|
|
3050
|
+
* @param graphUris URIs of the graphs to search for concepts.
|
|
3051
|
+
* @param subjectUri URI of a concept.
|
|
3052
|
+
* @param schemeUri URI of a concept scheme.
|
|
3053
|
+
* @returns `true` if the concept can be displayed below the concept scheme, `false` otherwise.
|
|
3054
|
+
*/
|
|
3055
|
+
_isVisibleInScheme(graphUris, subjectUri, schemeUri) {
|
|
3056
|
+
if (this.isConceptOfScheme(graphUris, subjectUri, schemeUri)) {
|
|
3057
|
+
return true;
|
|
3058
|
+
}
|
|
3059
|
+
return !this.hasConceptScheme(graphUris, subjectUri);
|
|
3060
|
+
}
|
|
3061
|
+
/**
|
|
3062
|
+
* Get the concepts that are explicitly associated with a concept scheme, either via
|
|
3063
|
+
* `skos:inScheme` or via `skos:topConceptOf`.
|
|
3064
|
+
* @param graphUris URIs of the graphs to search for concepts.
|
|
3065
|
+
* @param schemeUri URI of a concept scheme.
|
|
3066
|
+
* @returns An iterator of URIs of the concepts of the concept scheme.
|
|
3067
|
+
*/
|
|
3068
|
+
*getConceptsOfScheme(graphUris, schemeUri) {
|
|
3069
|
+
const yielded = /* @__PURE__ */ new Set();
|
|
3070
|
+
const o = dataFactory.namedNode(schemeUri);
|
|
3071
|
+
for (let q of this.store.matchAll(graphUris, null, skos.inScheme, o)) {
|
|
2963
3072
|
const s = q.subject;
|
|
2964
3073
|
if (!yielded.has(s.value)) {
|
|
2965
3074
|
yielded.add(s.value);
|
|
2966
3075
|
yield s.value;
|
|
2967
3076
|
}
|
|
2968
3077
|
}
|
|
3078
|
+
for (let q of this.store.matchAll(graphUris, null, skos.topConceptOf, o)) {
|
|
3079
|
+
const s = q.subject;
|
|
3080
|
+
if (!yielded.has(s.value)) {
|
|
3081
|
+
yielded.add(s.value);
|
|
3082
|
+
yield s.value;
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
/**
|
|
3087
|
+
* Get the top concepts of a concept scheme.
|
|
3088
|
+
*
|
|
3089
|
+
* In addition to the concepts that are explicitly designated as top concepts via
|
|
3090
|
+
* `skos:hasTopConcept` or `skos:topConceptOf`, this returns the concepts of the scheme that have
|
|
3091
|
+
* no broader concept *within the same scheme*. Without the latter, concepts whose `skos:broader`
|
|
3092
|
+
* property refers to a concept of another scheme would not be displayed below the scheme that
|
|
3093
|
+
* they are associated with.
|
|
3094
|
+
*
|
|
3095
|
+
* Note: A concept that is its own broader concept is not excluded, so that recursive definitions
|
|
3096
|
+
* do not remove it from the list of top concepts.
|
|
3097
|
+
* @param graphUris URIs of the graphs to search for concepts.
|
|
3098
|
+
* @param schemeUri URI of a concept scheme.
|
|
3099
|
+
* @returns An iterator of URIs of the top concepts of the concept scheme.
|
|
3100
|
+
*/
|
|
3101
|
+
*getTopConcepts(graphUris, schemeUri) {
|
|
3102
|
+
const yielded = /* @__PURE__ */ new Set();
|
|
3103
|
+
const s = dataFactory.namedNode(schemeUri);
|
|
3104
|
+
for (let q of this.store.matchAll(graphUris, s, skos.hasTopConcept, null)) {
|
|
3105
|
+
const o = q.object;
|
|
3106
|
+
if (!yielded.has(o.value)) {
|
|
3107
|
+
yielded.add(o.value);
|
|
3108
|
+
yield o.value;
|
|
3109
|
+
}
|
|
3110
|
+
}
|
|
3111
|
+
for (let q of this.store.matchAll(graphUris, null, skos.topConceptOf, s)) {
|
|
3112
|
+
const o = q.subject;
|
|
3113
|
+
if (!yielded.has(o.value)) {
|
|
3114
|
+
yielded.add(o.value);
|
|
3115
|
+
yield o.value;
|
|
3116
|
+
}
|
|
3117
|
+
}
|
|
3118
|
+
for (let q of this.store.matchAll(graphUris, s, skos.narrower, null)) {
|
|
3119
|
+
const o = q.object;
|
|
3120
|
+
if (!yielded.has(o.value)) {
|
|
3121
|
+
yielded.add(o.value);
|
|
3122
|
+
yield o.value;
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
for (let q of this.store.matchAll(graphUris, null, skos.broader, s)) {
|
|
3126
|
+
const o = q.subject;
|
|
3127
|
+
if (!yielded.has(o.value)) {
|
|
3128
|
+
yielded.add(o.value);
|
|
3129
|
+
yield o.value;
|
|
3130
|
+
}
|
|
3131
|
+
}
|
|
3132
|
+
const concepts = new Set(this.getConceptsOfScheme(graphUris, schemeUri));
|
|
3133
|
+
const nested = this._nestedConceptsOfScheme(graphUris, concepts);
|
|
3134
|
+
for (let c of concepts) {
|
|
3135
|
+
if (!yielded.has(c) && !nested.has(c)) {
|
|
3136
|
+
yielded.add(c);
|
|
3137
|
+
yield c;
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
}
|
|
3141
|
+
/**
|
|
3142
|
+
* Get the concepts of a concept scheme that have a broader concept within the same scheme.
|
|
3143
|
+
*
|
|
3144
|
+
* The hierarchical relations are enumerated once and matched against the set of concepts of the
|
|
3145
|
+
* scheme, which is considerably cheaper than querying the broader concepts of every single
|
|
3146
|
+
* concept of the scheme.
|
|
3147
|
+
* @param graphUris URIs of the graphs to search for concepts.
|
|
3148
|
+
* @param concepts Set of the concepts that are associated with the concept scheme.
|
|
3149
|
+
* @returns A set of URIs of the concepts that are nested below another concept of the scheme.
|
|
3150
|
+
*/
|
|
3151
|
+
_nestedConceptsOfScheme(graphUris, concepts) {
|
|
3152
|
+
const result = /* @__PURE__ */ new Set();
|
|
3153
|
+
for (let q of this.store.matchAll(graphUris, null, skos.broader, null)) {
|
|
3154
|
+
if (q.subject.value !== q.object.value && concepts.has(q.subject.value) && concepts.has(q.object.value)) {
|
|
3155
|
+
result.add(q.subject.value);
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
for (let q of this.store.matchAll(graphUris, null, skos.narrower, null)) {
|
|
3159
|
+
if (q.subject.value !== q.object.value && concepts.has(q.subject.value) && concepts.has(q.object.value)) {
|
|
3160
|
+
result.add(q.object.value);
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
3163
|
+
return result;
|
|
3164
|
+
}
|
|
3165
|
+
/**
|
|
3166
|
+
* Get all concepts that are displayed below a concept scheme, including indirectly narrower ones.
|
|
3167
|
+
*
|
|
3168
|
+
* The traversal starts at the {@link getTopConcepts} of the scheme and follows the narrower
|
|
3169
|
+
* concepts that can be displayed below the scheme, so the result is exactly the set of concepts
|
|
3170
|
+
* that a hierarchical view of the scheme can reach.
|
|
3171
|
+
*
|
|
3172
|
+
* Note: The hierarchical relations of the graphs are indexed once per call instead of querying
|
|
3173
|
+
* the narrower concepts of every single concept, which is an order of magnitude faster on large
|
|
3174
|
+
* thesauri. Prefer {@link getConceptsOfScheme} when the *associated* concepts are sufficient.
|
|
3175
|
+
* @param graphUris URIs of the graphs to search for concepts.
|
|
3176
|
+
* @param schemeUri URI of a concept scheme.
|
|
3177
|
+
* @returns An iterator of URIs of all concepts below the concept scheme.
|
|
3178
|
+
*/
|
|
3179
|
+
*getAllConceptsInScheme(graphUris, schemeUri) {
|
|
3180
|
+
const concepts = new Set(this.getConceptsOfScheme(graphUris, schemeUri));
|
|
3181
|
+
const narrowerConcepts = this._getNarrowerConceptIndex(graphUris);
|
|
3182
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3183
|
+
const stack = [...this.getTopConcepts(graphUris, schemeUri)];
|
|
3184
|
+
for (let c of stack) {
|
|
3185
|
+
visited.add(c);
|
|
3186
|
+
}
|
|
3187
|
+
while (stack.length) {
|
|
3188
|
+
const current = stack.pop();
|
|
3189
|
+
yield current;
|
|
3190
|
+
for (let n of narrowerConcepts.get(current) ?? []) {
|
|
3191
|
+
if (visited.has(n)) {
|
|
3192
|
+
continue;
|
|
3193
|
+
}
|
|
3194
|
+
if (!concepts.has(n) && this.hasConceptScheme(graphUris, n)) {
|
|
3195
|
+
continue;
|
|
3196
|
+
}
|
|
3197
|
+
visited.add(n);
|
|
3198
|
+
stack.push(n);
|
|
3199
|
+
}
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
/**
|
|
3203
|
+
* Index the narrower concept relations of the given graphs.
|
|
3204
|
+
*
|
|
3205
|
+
* All four hierarchical relations are enumerated once, which is considerably cheaper than
|
|
3206
|
+
* querying {@link getNarrowerConcepts} for every concept of a large thesaurus.
|
|
3207
|
+
* @param graphUris URIs of the graphs to search for concepts.
|
|
3208
|
+
* @returns A map of concept URIs to the URIs of their narrower concepts.
|
|
3209
|
+
*/
|
|
3210
|
+
_getNarrowerConceptIndex(graphUris) {
|
|
3211
|
+
const result = /* @__PURE__ */ new Map();
|
|
3212
|
+
const add = (broaderUri, narrowerUri) => {
|
|
3213
|
+
const narrowerConcepts = result.get(broaderUri);
|
|
3214
|
+
if (narrowerConcepts) {
|
|
3215
|
+
narrowerConcepts.push(narrowerUri);
|
|
3216
|
+
} else {
|
|
3217
|
+
result.set(broaderUri, [narrowerUri]);
|
|
3218
|
+
}
|
|
3219
|
+
};
|
|
3220
|
+
for (let q of this.store.matchAll(graphUris, null, skos.narrower, null)) {
|
|
3221
|
+
add(q.subject.value, q.object.value);
|
|
3222
|
+
}
|
|
3223
|
+
for (let q of this.store.matchAll(graphUris, null, skos.broader, null)) {
|
|
3224
|
+
add(q.object.value, q.subject.value);
|
|
3225
|
+
}
|
|
3226
|
+
for (let q of this.store.matchAll(graphUris, null, skos.hasTopConcept, null)) {
|
|
3227
|
+
add(q.subject.value, q.object.value);
|
|
3228
|
+
}
|
|
3229
|
+
for (let q of this.store.matchAll(graphUris, null, skos.topConceptOf, null)) {
|
|
3230
|
+
add(q.object.value, q.subject.value);
|
|
3231
|
+
}
|
|
3232
|
+
return result;
|
|
2969
3233
|
}
|
|
2970
3234
|
/**
|
|
2971
3235
|
* Get the members of a collection. This includes both `skos:member` and `skos:memberList` properties.
|
|
@@ -3013,6 +3277,234 @@ var ConceptRepository = class extends ResourceRepository {
|
|
|
3013
3277
|
}
|
|
3014
3278
|
return false;
|
|
3015
3279
|
}
|
|
3280
|
+
/**
|
|
3281
|
+
* Indicates whether a subject is a collection.
|
|
3282
|
+
* @param graphUris URI of the graphs to search for collections.
|
|
3283
|
+
* @param subjectUri URI of a subject.
|
|
3284
|
+
* @returns `true` if the subject is a `skos:Collection` or a `skos:OrderedCollection`, `false` otherwise.
|
|
3285
|
+
*/
|
|
3286
|
+
isCollection(graphUris, subjectUri) {
|
|
3287
|
+
if (subjectUri) {
|
|
3288
|
+
const s = dataFactory.namedNode(subjectUri);
|
|
3289
|
+
for (let _ of this.store.matchAll(graphUris, s, rdf.type, skos.Collection)) {
|
|
3290
|
+
return true;
|
|
3291
|
+
}
|
|
3292
|
+
for (let _ of this.store.matchAll(graphUris, s, rdf.type, skos.OrderedCollection)) {
|
|
3293
|
+
return true;
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
return false;
|
|
3297
|
+
}
|
|
3298
|
+
/**
|
|
3299
|
+
* Get the collections that have a given subject as a member. This includes both `skos:member`
|
|
3300
|
+
* and `skos:memberList` properties.
|
|
3301
|
+
*
|
|
3302
|
+
* Note: A collection that is a member of itself is returned as its own super collection, which
|
|
3303
|
+
* is consistent with {@link getBroaderConcepts}. Use {@link hasSuperCollections} to test whether
|
|
3304
|
+
* a collection is a member of *another* collection.
|
|
3305
|
+
* @param graphUris URI of the graphs to search for collections.
|
|
3306
|
+
* @param subjectUri URI of a collection or concept.
|
|
3307
|
+
* @returns An iterator of URIs of the collections that contain the subject.
|
|
3308
|
+
*/
|
|
3309
|
+
*getSuperCollections(graphUris, subjectUri) {
|
|
3310
|
+
const yielded = /* @__PURE__ */ new Set();
|
|
3311
|
+
const o = dataFactory.namedNode(subjectUri);
|
|
3312
|
+
for (let q of this.store.matchAll(graphUris, null, skos.member, o)) {
|
|
3313
|
+
const s = q.subject;
|
|
3314
|
+
if (!yielded.has(s.value) && this.isCollection(graphUris, s.value)) {
|
|
3315
|
+
yielded.add(s.value);
|
|
3316
|
+
yield s.value;
|
|
3317
|
+
}
|
|
3318
|
+
}
|
|
3319
|
+
for (let s of this._getMemberListContainers(graphUris, subjectUri)) {
|
|
3320
|
+
if (!yielded.has(s) && this.isCollection(graphUris, s)) {
|
|
3321
|
+
yielded.add(s);
|
|
3322
|
+
yield s;
|
|
3323
|
+
}
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
/**
|
|
3327
|
+
* Get the collections that reference a given subject in an ordered member list.
|
|
3328
|
+
*
|
|
3329
|
+
* Starting from the list nodes that have the subject as their first item, the `rdf:rest` chain
|
|
3330
|
+
* is traversed *backwards* towards the head of the list, and every visited list node is tested
|
|
3331
|
+
* for being the object of a `skos:memberList` property. This is considerably cheaper than
|
|
3332
|
+
* expanding all member lists in the graph, and it also resolves collections that share a list.
|
|
3333
|
+
* @param graphUris URI of the graphs to search for collections.
|
|
3334
|
+
* @param subjectUri URI of a collection or concept.
|
|
3335
|
+
* @returns An iterator of URIs of the collections that reference the subject in a member list.
|
|
3336
|
+
*/
|
|
3337
|
+
*_getMemberListContainers(graphUris, subjectUri) {
|
|
3338
|
+
const o = dataFactory.namedNode(subjectUri);
|
|
3339
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3340
|
+
const listNodes = [];
|
|
3341
|
+
for (let q of this.store.matchAll(graphUris, null, rdf.first, o)) {
|
|
3342
|
+
if (!visited.has(q.subject.value)) {
|
|
3343
|
+
visited.add(q.subject.value);
|
|
3344
|
+
listNodes.push(q.subject);
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
while (listNodes.length) {
|
|
3348
|
+
const listNode = listNodes.pop();
|
|
3349
|
+
for (let q of this.store.matchAll(graphUris, null, skos.memberList, listNode)) {
|
|
3350
|
+
yield q.subject.value;
|
|
3351
|
+
}
|
|
3352
|
+
for (let q of this.store.matchAll(graphUris, null, rdf.rest, listNode)) {
|
|
3353
|
+
if (!visited.has(q.subject.value)) {
|
|
3354
|
+
visited.add(q.subject.value);
|
|
3355
|
+
listNodes.push(q.subject);
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
}
|
|
3359
|
+
}
|
|
3360
|
+
/**
|
|
3361
|
+
* Indicates whether a collection is a member of another collection.
|
|
3362
|
+
*
|
|
3363
|
+
* Note: A collection that is a member of itself is *not* considered to have a super collection,
|
|
3364
|
+
* so that recursive definitions do not remove it from the list of root collections.
|
|
3365
|
+
* @param graphUris URI of the graphs to search for collections.
|
|
3366
|
+
* @param subjectUri URI of a collection.
|
|
3367
|
+
* @returns `true` if the collection is a member of another collection, `false` otherwise.
|
|
3368
|
+
*/
|
|
3369
|
+
hasSuperCollections(graphUris, subjectUri) {
|
|
3370
|
+
for (const c of this.getSuperCollections(graphUris, subjectUri)) {
|
|
3371
|
+
if (c !== subjectUri) {
|
|
3372
|
+
return true;
|
|
3373
|
+
}
|
|
3374
|
+
}
|
|
3375
|
+
return false;
|
|
3376
|
+
}
|
|
3377
|
+
/**
|
|
3378
|
+
* Get the members of a collection that are collections themselves, or all root collections.
|
|
3379
|
+
*
|
|
3380
|
+
* The order of the members of a `skos:OrderedCollection` is preserved.
|
|
3381
|
+
* @param graphUris URI of the graphs to search for collections.
|
|
3382
|
+
* @param subjectUri URI of a collection or `undefined` to get all root collections.
|
|
3383
|
+
* @param options Optional query parameters.
|
|
3384
|
+
* @returns An iterator of URIs of the nested collections of the given collection, or of the root collections if no subject is provided.
|
|
3385
|
+
*/
|
|
3386
|
+
*getSubCollections(graphUris, subjectUri, options) {
|
|
3387
|
+
if (subjectUri) {
|
|
3388
|
+
const yielded = /* @__PURE__ */ new Set();
|
|
3389
|
+
for (let m of this.getCollectionMembers(graphUris, subjectUri)) {
|
|
3390
|
+
if (yielded.has(m) || !this.isCollection(graphUris, m)) {
|
|
3391
|
+
continue;
|
|
3392
|
+
}
|
|
3393
|
+
if (this._skipCollection(graphUris, dataFactory.namedNode(m), options)) {
|
|
3394
|
+
continue;
|
|
3395
|
+
}
|
|
3396
|
+
yielded.add(m);
|
|
3397
|
+
yield m;
|
|
3398
|
+
}
|
|
3399
|
+
} else {
|
|
3400
|
+
yield* this.getRootCollections(graphUris, options);
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
/**
|
|
3404
|
+
* Indicates whether a collection has members that are collections themselves.
|
|
3405
|
+
* @param graphUris URI of the graphs to search for collections.
|
|
3406
|
+
* @param subjectUri URI of a collection.
|
|
3407
|
+
* @param options Optional query parameters.
|
|
3408
|
+
* @returns `true` if the collection has nested collections, `false` otherwise.
|
|
3409
|
+
*/
|
|
3410
|
+
hasSubCollections(graphUris, subjectUri, options) {
|
|
3411
|
+
for (const _ of this.getSubCollections(graphUris, subjectUri, options)) {
|
|
3412
|
+
return true;
|
|
3413
|
+
}
|
|
3414
|
+
return false;
|
|
3415
|
+
}
|
|
3416
|
+
/**
|
|
3417
|
+
* Get all collections that are not a member of another collection.
|
|
3418
|
+
*
|
|
3419
|
+
* Every collection returned by {@link getCollections} is either returned by this method, or is
|
|
3420
|
+
* reachable from one of the returned collections via {@link getSubCollections}. If a group of
|
|
3421
|
+
* collections is only reachable through a membership cycle, the first collection of that group
|
|
3422
|
+
* is returned as a root collection so that no collection is lost.
|
|
3423
|
+
*
|
|
3424
|
+
* Note: Collections that are identified by a blank node cannot be queried for their members and
|
|
3425
|
+
* are therefore always returned as root collections.
|
|
3426
|
+
* @param graphUris URI of the graphs to search for collections.
|
|
3427
|
+
* @param options Optional query parameters.
|
|
3428
|
+
* @returns An iterator of URIs of the root collections.
|
|
3429
|
+
*/
|
|
3430
|
+
*getRootCollections(graphUris, options) {
|
|
3431
|
+
const roots = /* @__PURE__ */ new Set();
|
|
3432
|
+
const collections = new Set(this.getCollections(graphUris, options));
|
|
3433
|
+
for (let c of collections) {
|
|
3434
|
+
if (!this.hasSuperCollections(graphUris, c)) {
|
|
3435
|
+
roots.add(c);
|
|
3436
|
+
yield c;
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
if (roots.size === collections.size) {
|
|
3440
|
+
return;
|
|
3441
|
+
}
|
|
3442
|
+
const reachable = new Set(roots);
|
|
3443
|
+
for (let c of roots) {
|
|
3444
|
+
this._markReachableCollections(graphUris, c, collections, reachable);
|
|
3445
|
+
}
|
|
3446
|
+
for (let c of collections) {
|
|
3447
|
+
if (!reachable.has(c)) {
|
|
3448
|
+
reachable.add(c);
|
|
3449
|
+
this._markReachableCollections(graphUris, c, collections, reachable);
|
|
3450
|
+
yield c;
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3454
|
+
/**
|
|
3455
|
+
* Mark all collections that can be reached from a given collection through nested collections.
|
|
3456
|
+
*
|
|
3457
|
+
* The traversal uses the same criteria as {@link getSubCollections} so that the marked
|
|
3458
|
+
* collections are exactly the collections that are visible below the given collection. Since
|
|
3459
|
+
* the set of reachable collections is shared between all calls, the members of a collection are
|
|
3460
|
+
* enumerated at most once per {@link getRootCollections} call.
|
|
3461
|
+
* @param graphUris URI of the graphs to search for collections.
|
|
3462
|
+
* @param subjectUri URI of the collection to start the traversal from.
|
|
3463
|
+
* @param collections Set of all collections that are in the scope of the query.
|
|
3464
|
+
* @param reachable Set of collections that have already been reached.
|
|
3465
|
+
*/
|
|
3466
|
+
_markReachableCollections(graphUris, subjectUri, collections, reachable) {
|
|
3467
|
+
const stack = [subjectUri];
|
|
3468
|
+
while (stack.length) {
|
|
3469
|
+
const current = stack.pop();
|
|
3470
|
+
for (let m of this.getCollectionMembers(graphUris, current)) {
|
|
3471
|
+
if (collections.has(m) && !reachable.has(m) && this.isCollection(graphUris, m)) {
|
|
3472
|
+
reachable.add(m);
|
|
3473
|
+
stack.push(m);
|
|
3474
|
+
}
|
|
3475
|
+
}
|
|
3476
|
+
}
|
|
3477
|
+
}
|
|
3478
|
+
/**
|
|
3479
|
+
* Get the first discovered path from a given collection to a root collection.
|
|
3480
|
+
*
|
|
3481
|
+
* The path does not contain the given collection and is ordered from the closest super
|
|
3482
|
+
* collection to the root collection. If the collection is part of a membership cycle, the path
|
|
3483
|
+
* ends at the last collection that has not been visited yet and does not reach a root collection.
|
|
3484
|
+
* @param graphUris URI of the graphs to search for collections.
|
|
3485
|
+
* @param subjectUri URI of a collection.
|
|
3486
|
+
* @returns The first path that is found from the given collection to a root collection.
|
|
3487
|
+
*/
|
|
3488
|
+
getRootCollectionPath(graphUris, subjectUri) {
|
|
3489
|
+
return this._getRootCollectionPath(graphUris, subjectUri, [], /* @__PURE__ */ new Set([subjectUri]));
|
|
3490
|
+
}
|
|
3491
|
+
/**
|
|
3492
|
+
* Recursively find the first path from a given collection to a root collection.
|
|
3493
|
+
* @param graphUris URI of the graphs to search for collections.
|
|
3494
|
+
* @param subjectUri URI of a collection.
|
|
3495
|
+
* @param path The current collection path.
|
|
3496
|
+
* @param backtrack Set of URIs that have already been visited.
|
|
3497
|
+
* @returns The first path that is found from the given collection to a root collection.
|
|
3498
|
+
*/
|
|
3499
|
+
_getRootCollectionPath(graphUris, subjectUri, path, backtrack) {
|
|
3500
|
+
for (let o of this.getSuperCollections(graphUris, subjectUri)) {
|
|
3501
|
+
if (!backtrack.has(o)) {
|
|
3502
|
+
backtrack.add(o);
|
|
3503
|
+
return this._getRootCollectionPath(graphUris, o, [...path, o], backtrack);
|
|
3504
|
+
}
|
|
3505
|
+
}
|
|
3506
|
+
return path;
|
|
3507
|
+
}
|
|
3016
3508
|
/**
|
|
3017
3509
|
* Get all broader concepts of a concept scheme.
|
|
3018
3510
|
* @param graphUris URIs of the graphs to search for concepts.
|
|
@@ -3062,44 +3554,58 @@ var ConceptRepository = class extends ResourceRepository {
|
|
|
3062
3554
|
return false;
|
|
3063
3555
|
}
|
|
3064
3556
|
/**
|
|
3065
|
-
* Get all narrower concepts of a concept or top concepts of a concept scheme.
|
|
3557
|
+
* Get all narrower concepts of a concept or the top concepts of a concept scheme.
|
|
3558
|
+
*
|
|
3559
|
+
* If the subject is a concept scheme, the {@link getTopConcepts} of that scheme are returned. If
|
|
3560
|
+
* the `inScheme` option is set, only concepts that can be displayed below that concept scheme are
|
|
3561
|
+
* returned, which excludes concepts that are associated with a *different* scheme.
|
|
3066
3562
|
* @param graphUris URIs of the graphs to search for concepts.
|
|
3067
|
-
* @param subjectUri URI of a concept or concept scheme.
|
|
3563
|
+
* @param subjectUri URI of a concept or concept scheme, or `undefined` to get all concept schemes.
|
|
3564
|
+
* @param options Optional query parameters.
|
|
3068
3565
|
*/
|
|
3069
|
-
*getNarrowerConcepts(graphUris, subjectUri) {
|
|
3070
|
-
if (subjectUri) {
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3566
|
+
*getNarrowerConcepts(graphUris, subjectUri, options) {
|
|
3567
|
+
if (!subjectUri) {
|
|
3568
|
+
yield* this.getConceptSchemes(graphUris);
|
|
3569
|
+
return;
|
|
3570
|
+
}
|
|
3571
|
+
if (this.isConceptScheme(graphUris, subjectUri)) {
|
|
3572
|
+
yield* this.getTopConcepts(graphUris, subjectUri);
|
|
3573
|
+
return;
|
|
3574
|
+
}
|
|
3575
|
+
const yielded = /* @__PURE__ */ new Set();
|
|
3576
|
+
const s = dataFactory.namedNode(subjectUri);
|
|
3577
|
+
const scheme = options?.inScheme;
|
|
3578
|
+
for (let q of this.store.matchAll(graphUris, s, skos.hasTopConcept, null)) {
|
|
3579
|
+
const o = q.object;
|
|
3580
|
+
if (!yielded.has(o.value)) {
|
|
3581
|
+
yielded.add(o.value);
|
|
3582
|
+
yield o.value;
|
|
3079
3583
|
}
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3584
|
+
}
|
|
3585
|
+
for (let q of this.store.matchAll(graphUris, s, skos.narrower, null)) {
|
|
3586
|
+
const o = q.object;
|
|
3587
|
+
if (!yielded.has(o.value)) {
|
|
3588
|
+
yielded.add(o.value);
|
|
3589
|
+
if (!scheme || this._isVisibleInScheme(graphUris, o.value, scheme)) {
|
|
3084
3590
|
yield o.value;
|
|
3085
3591
|
}
|
|
3086
3592
|
}
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3593
|
+
}
|
|
3594
|
+
for (let q of this.store.matchAll(graphUris, null, skos.topConceptOf, s)) {
|
|
3595
|
+
const o = q.subject;
|
|
3596
|
+
if (!yielded.has(o.value)) {
|
|
3597
|
+
yielded.add(o.value);
|
|
3598
|
+
yield o.value;
|
|
3093
3599
|
}
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3600
|
+
}
|
|
3601
|
+
for (let q of this.store.matchAll(graphUris, null, skos.broader, s)) {
|
|
3602
|
+
const o = q.subject;
|
|
3603
|
+
if (!yielded.has(o.value)) {
|
|
3604
|
+
yielded.add(o.value);
|
|
3605
|
+
if (!scheme || this._isVisibleInScheme(graphUris, o.value, scheme)) {
|
|
3606
|
+
yield o.value;
|
|
3099
3607
|
}
|
|
3100
3608
|
}
|
|
3101
|
-
} else {
|
|
3102
|
-
yield* this.getConceptSchemes(graphUris);
|
|
3103
3609
|
}
|
|
3104
3610
|
}
|
|
3105
3611
|
/**
|
|
@@ -3144,7 +3650,7 @@ var ConceptRepository = class extends ResourceRepository {
|
|
|
3144
3650
|
* @param subjectUri URI of a concept.
|
|
3145
3651
|
*/
|
|
3146
3652
|
getConceptSchemePath(graphUris, subjectUri) {
|
|
3147
|
-
return this._getConceptSchemePath(graphUris, subjectUri, [], /* @__PURE__ */ new Set());
|
|
3653
|
+
return this._getConceptSchemePath(graphUris, subjectUri, [], /* @__PURE__ */ new Set([subjectUri]));
|
|
3148
3654
|
}
|
|
3149
3655
|
/**
|
|
3150
3656
|
* Recursively find the first path from a given class to a root class.
|
|
@@ -3154,9 +3660,11 @@ var ConceptRepository = class extends ResourceRepository {
|
|
|
3154
3660
|
* @returns The first path that is found from the given class to a root class.
|
|
3155
3661
|
*/
|
|
3156
3662
|
_getConceptSchemePath(graphUris, subjectUri, path, backtrack) {
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3663
|
+
for (let o of this.getBroaderConcepts(graphUris, subjectUri)) {
|
|
3664
|
+
if (!backtrack.has(o)) {
|
|
3665
|
+
backtrack.add(o);
|
|
3666
|
+
return this._getConceptSchemePath(graphUris, o, [...path, o], backtrack);
|
|
3667
|
+
}
|
|
3160
3668
|
}
|
|
3161
3669
|
return path;
|
|
3162
3670
|
}
|
|
@@ -8985,7 +9493,18 @@ var Store = class {
|
|
|
8985
9493
|
const list = listUri.includes(":") ? this.dataFactory.namedNode(listUri) : this.dataFactory.blankNode(listUri);
|
|
8986
9494
|
return this._getListItems(graphUris, list).map((t) => t.value);
|
|
8987
9495
|
}
|
|
8988
|
-
|
|
9496
|
+
/**
|
|
9497
|
+
* Recursively collect the items of an ordered list.
|
|
9498
|
+
* @param graphUris Optional graph URI or array of graph URIs to query.
|
|
9499
|
+
* @param subject The list node to collect the items from.
|
|
9500
|
+
* @param visited Set of list nodes that have already been visited.
|
|
9501
|
+
* @returns An array of the items in the list.
|
|
9502
|
+
*/
|
|
9503
|
+
_getListItems(graphUris, subject, visited = /* @__PURE__ */ new Set()) {
|
|
9504
|
+
if (visited.has(subject.value)) {
|
|
9505
|
+
return [];
|
|
9506
|
+
}
|
|
9507
|
+
visited.add(subject.value);
|
|
8989
9508
|
const first = Array.from(this.matchAll(graphUris, subject, rdf.first, null));
|
|
8990
9509
|
if (!first.length) {
|
|
8991
9510
|
return [];
|
|
@@ -8993,10 +9512,10 @@ var Store = class {
|
|
|
8993
9512
|
const rest = Array.from(this.matchAll(graphUris, subject, rdf.rest, null));
|
|
8994
9513
|
const firstItem = first[0].object;
|
|
8995
9514
|
const restList = rest[0]?.object;
|
|
8996
|
-
if (restList.value === RDF.nil) {
|
|
9515
|
+
if (!restList || restList.value === RDF.nil) {
|
|
8997
9516
|
return [firstItem];
|
|
8998
9517
|
} else {
|
|
8999
|
-
const restItems = this._getListItems(graphUris, restList);
|
|
9518
|
+
const restItems = this._getListItems(graphUris, restList, visited);
|
|
9000
9519
|
return [firstItem, ...restItems];
|
|
9001
9520
|
}
|
|
9002
9521
|
}
|