All files / rdf vocabulary-repository.ts

100% Statements 49/49
96% Branches 24/25
100% Functions 6/6
100% Lines 49/49

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160          4x                       6x   6x 8x   8x 1x     7x 4x   4x                     2x 1x     1x                 11x   11x 8x   8x 1x     7x 7x   7x                     2x 1x     1x                   4x   4x   4x   4x     3x   1x                         5x     5x       5x 4x   4x     5x 3009x 3009x   3009x 416x         2593x 2593x   2593x   2593x     2590x 200x   2390x     2590x 36x   36x          
import { rdf, rdfs, owl, skos } from "../ontologies";
import { Uri } from "./uri";
import { ShapeRepository } from "./shape-repository";
import { dataFactory } from "./data-factory";
 
const { namedNode } = dataFactory;
 
/**
 * A repository for retrieving ontologies and ontology concepts from graphs.
 */
export class VocabularyRepository extends ShapeRepository {
    /**
     * Get all concept schemes in the repository.
     * @param graphUris URIs of the graphs to search.
     * @returns An iterator of all concept schemes in the repository.
     */
    public *getConceptSchemes(graphUris: string | string[] | undefined): IterableIterator<string> {
        const yielded = new Set<string>();
 
        for (const q of this.store.matchAll(graphUris, null, rdf.type, skos.ConceptScheme)) {
            const s = q.subject;
 
            if (s.termType != "NamedNode") {
                continue;
            }
 
            if (!yielded.has(s.value)) {
                yielded.add(s.value);
 
                yield s.value;
            }
        }
    }
 
    /**
     * Indicates whether the repository contains any concept schemes.
     * @param graphUris URIs of the graphs to search.
     * @returns `true` if the repository contains any concept schemes, `false` otherwise.
     */
    public hasConceptSchemes(graphUris: string | string[] | undefined): boolean {
        for(const _ of this.getConceptSchemes(graphUris)) {
            return true;
        }
 
        return false;
    }
 
    /**
     * Get all ontologies in the repository.
     * @param graphUris URIs of the graphs to search.
     * @returns An iterator of all ontologies in the repository.
     */
    public *getOntologies(graphUris: string | string[] | undefined): IterableIterator<string> {
        const yielded = new Set<string>();
 
        for (const q of this.store.matchAll(graphUris, null, rdf.type, owl.Ontology)) {
            const s = q.subject;
 
            if (s.termType != "NamedNode") {
                continue;
            }
 
            Eif (!yielded.has(s.value)) {
                yielded.add(s.value);
 
                yield s.value;
            }
        }
    }
 
    /**
     * Indicates whether the repository contains any ontology headers.
     * @param graphUris URIs of the graphs to search.
     * @returns `true` if the repository contains any ontology headers, `false` otherwise.
     */
    public hasOntologies(graphUris: string | string[] | undefined): boolean {
        for(const _ of this.getOntologies(graphUris)) {
            return true;
        }
 
        return false;
    }
 
    /**
     * Get the version (owl:versionInfo) of an ontology. If the version is a date, it is returned as a string in the format "YYYY-MM-DD".
     * @param graphUris URIs of the graphs to search.
     * @param ontologyUri URI of the ontology.
     * @returns The version of the ontology, or undefined if it is not found.
     */
    public getOntologyVersionInfo(graphUris: string | string[] | undefined, ontologyUri: string): string | undefined {
        const s = namedNode(ontologyUri);
 
        for (const q of this.store.matchAll(graphUris, s, owl.versionInfo, null)) {
            // If the version is a date, return it in the format "YYYY-MM-DD".
            const match = q.object.value.match(/(\d{4}[\/-]\d{2}[\/-]\d{2})/);
 
            if (match && match.length > 1) {
                // Don't rely on Date parsing or timezone conversions; keep it purely lexical.
                // The source is already YYYY-MM-DD or YYYY/MM/DD, normalize to YYYY-MM-DD.
                return match[1].replace(/\//g, '-');
            } else {
                return q.object.value;
            }
        }
    }
 
    /**
     * Get the sources of definitions for a given graph. These are ontology definitions 
     * or the objects of `rdfs:isDefinedBy` triples. If the rdfs:isDefinedBy object can be
     * matched with an ontology definition, the ontology URI is returned.
     * @param graphUris URIs of the graphs to search.
     * @returns An iterator of sources of definitions for the given graph.
     */
    public *getDefinitionSources(graphUris: string | string[] | undefined, includeOntologies = false): IterableIterator<string> {
        const yielded = new Set<string>();
 
        // Load all ontologies in the graph in a normalized form.
        const ontologies: { [key: string]: string } = {};
 
        // Store the normalized versions of the ontology URI so that we can detect 
        // equality even if different namespace seperators ('#' and '/') are used.
        for (let o of this.getOntologies(graphUris)) {
            const uri = Uri.getNormalizedUri(o);
 
            ontologies[uri] = o;
        }
 
        for (const q of this.store.matchAll(graphUris, null, rdfs.isDefinedBy, null)) {
            const s = q.subject;
            const o = q.object;
 
            if (s.termType != "NamedNode" || o.termType != "NamedNode") {
                continue;
            }
 
            // Do not include ontologies in the list of sources. However, if there are other
            // terms defined by the object it will be included by subsequent iterations.
            const s_ = Uri.getNormalizedUri(s.value);
            const o_ = Uri.getNormalizedUri(o.value);
 
            let isOntology = s_ in ontologies;
 
            if (!isOntology || includeOntologies) {
                let sourceValue: string;
 
                if (o_ in ontologies) {
                    sourceValue = ontologies[o_];
                } else {
                    sourceValue = o.value;
                }
 
                if (!yielded.has(sourceValue)) {
                    yielded.add(sourceValue);
 
                    yield sourceValue;
                }
            }
        }
    }
}