UNPKG

sparnatural

Version:

Visual client-side SPARQL query builder and knowledge graph exploration tool

329 lines 15.5 kB
import { DataFactory } from 'rdf-data-factory'; import { SHACLSpecificationEntry } from "./SHACLSpecificationEntry"; import { SHACLSpecificationProperty } from "./SHACLSpecificationProperty"; import { Dag } from "../../dag/Dag"; import { GEOSPARQL, Model, RDF, RDFS, SH, XSD, DatatypeRegistry } from 'rdf-shacl-commons'; const factory = new DataFactory(); export class SHACLSpecificationEntity extends SHACLSpecificationEntry { constructor(uri, provider, n3store, lang) { super(uri, provider, n3store, lang); } getLabel() { return this.shape.getLabel(this.lang); } getTooltip() { return this.shape.getTooltip(this.lang); } getConnectingProperties(range) { // read all sh:property and find the ones that can target the selected class var items = []; let propShapes = this.getProperties(); propShapes.forEach(ps => { let prop = new SHACLSpecificationProperty(ps, this.provider, this.store, this.lang); let pRange = prop.getRange(); if (pRange.indexOf(range) > -1) { items.push(ps); } }); // add properties available from parents - recursively let parents = this.provider.getEntity(range).getParents(); parents.forEach(aParent => { items = [...items, ...this.getConnectingProperties(aParent)]; }); // dedup, although probably dedup is not necessary here var dedupItems = [...new Set(items)]; // sort dedups var sortedDedups = SHACLSpecificationEntry.sort(dedupItems.map(s => new SHACLSpecificationProperty(s, this.provider, this.store, this.lang))); // return dedup array of strings return sortedDedups.map(e => e.getId()); } /** * Return the tree of properties connecting this entity to the specified range entity * @param range The URI of the selected target entity * @returns */ getConnectingPropertiesTree(range) { // 1. get list of properties let properties = this.getConnectingProperties(range).map(s => this.provider.getProperty(s)); // retrieve the potential parents while (!properties.every(property => { return property.getParents().every(parent => { return (properties.find(anotherProperty => anotherProperty.getId() === parent) != undefined); }); })) { let parentsToAdd = []; properties.forEach(property => { property.getParents().forEach(parent => { // if the parent is not already there, add it to the list of parents to add if (!properties.find(anotherProperty => anotherProperty.getId() === parent)) { parentsToAdd.push(this.provider.getProperty(parent)); } }); }); parentsToAdd.forEach(p => properties.push(p)); } // 2. turn it into a tree let dag = new Dag(); dag.initFromParentableAndIdAbleEntity(properties, []); // sort the tree with compare function dag.sort(SHACLSpecificationProperty.compare); return dag; } getConnectedEntities() { var items = []; // read all properties that make sense for Sparnatural let propShapes = this.getProperties(); propShapes .forEach(ps => { // read the property let prop = new SHACLSpecificationProperty(ps, this.provider, this.store, this.lang); // and then read their ranges items.push(...prop.getRange()); }); // dedup var dedupItems = [...new Set(items)]; // sort dedups var sortedDedups = SHACLSpecificationEntry.sort(dedupItems.map(s => new SHACLSpecificationEntity(s, this.provider, this.store, this.lang))); // return dedup array of strings return sortedDedups.map(e => e.getId()); } getConnectedEntitiesTree() { // 1. get directly connected entities let entities = this.getConnectedEntities().map(s => this.provider.getEntity(s)); // 2. add the children of these entities - recursively while (!entities.every(entity => { return entity.getChildren().every(child => { return (entities.find(anotherEntity => anotherEntity.getId() === child) != undefined); }); })) { let childrenToAdd = []; entities.forEach(entity => { entity.getChildren().forEach(child => { if (!entities.find(anotherEntity => anotherEntity.getId() === child)) { childrenToAdd.push(this.provider.getEntity(child)); } }); }); childrenToAdd.forEach(p => entities.push(p)); } // 3. complement the initial list with their parents let disabledList = new Array(); // while not all parents of all entities are not part of the list... while (!entities.every(entity => { return entity.getParents().every(parent => { return (entities.find(anotherEntity => anotherEntity.getId() === parent) != undefined); }); })) { let parentsToAdd = []; entities.forEach(entity => { entity.getParents().forEach(parent => { if (!entities.find(anotherEntity => anotherEntity.getId() === parent)) { parentsToAdd.push(this.provider.getEntity(parent)); } }); }); parentsToAdd.forEach(p => entities.push(p)); // also keep that as a disabled node parentsToAdd.forEach(p => disabledList.push(p.getId())); } let dag = new Dag(); dag.initFromParentableAndIdAbleEntity(entities, disabledList); // sort the tree with compare function dag.sort(SHACLSpecificationEntity.compare); return dag; } hasConnectedEntities() { return (this.getConnectedEntities().length > 0); } /** * @returns all (non-deactivated) properties available on this node shape, including inherited properties from superclasses */ getProperties() { var items = []; let propertyShapes = this.shape.getProperties(); // filter properties not to be shown propertyShapes .forEach(ps => { if (SHACLSpecificationProperty.isSparnaturalSHACLSpecificationProperty(ps.resource.value, this.store)) { items.push(ps.resource.value); } }); // dedup, although probably dedup is not necessary here var dedupItems = [...new Set(items)]; // sort dedups var sortedDedups = SHACLSpecificationEntry.sort(dedupItems.map(s => new SHACLSpecificationProperty(s, this.provider, this.store, this.lang))); // return dedup array of strings return sortedDedups.map(e => e.getId()); } /** * * @returns true if sh:nodeKind = sh:Literal, or if sh:datatype is present, or if sh:languageIn is present */ isLiteralEntity() { return this.shape.isLiteral(); } isBlankNodeEntity() { return this.shape.isBlankNode(); } /** * @returns true if this shape has a target, either a targetClass or sh:target, or is itself a Class */ hasTypeCriteria() { var hasTargetClass = this.graph.hasTriple(factory.namedNode(this.uri), SH.TARGET_CLASS, null); var hasTarget = this.graph.hasTriple(factory.namedNode(this.uri), SH.TARGET, null); var isItselfClass = this.graph.hasTriple(factory.namedNode(this.uri), RDF.TYPE, RDFS.CLASS); return (hasTargetClass || hasTarget || isItselfClass); } /** * @returns a property labelled with dash:propertyRole = dash:LabelRole */ getDefaultLabelProperty() { return this.shape.getDefaultLabelProperty()?.resource.value; } getParents() { return this.shape.getParents().map(r => r.value); } getChildren() { return this.shape.getChildren().map(r => r.value); } /** * @returns all values of sh:targetClass on this entity, as RDF Terms */ getShTargetClass() { return this.shape.getShTargetClass(); } /** * @returns true if this shape as an sh:target predicate (indicating it is associated to a SPARQL query target) */ hasShTarget() { return this.shape.getShTarget()?.length > 0; } couldBeSkosConcept() { return this.shape.couldBeSkosConcept(); } static compare(item1, item2) { return SHACLSpecificationEntry.compare(item1, item2); } } export class SpecialSHACLSpecificationEntity { constructor(id, icon, label, isRangeOfFunction) { this.id = id; this.icon = icon; this.label = label; this.isRangeOfFunction = isRangeOfFunction; } getId() { return this.id; } getLabel() { return this.label; } getColor() { // return "slategray"; return undefined; } getIcon() { return this.icon; } isRangeOf(n3store, shapeUri) { return this.isRangeOfFunction(n3store, shapeUri); } // default implementation of all other functions getConnectedEntities() { return new Array(); } getConnectedEntitiesTree() { return new Dag(); } hasConnectedEntities() { return false; } getConnectingProperties(range) { return new Array(); } getConnectingPropertiesTree(range) { return new Dag(); } isLiteralEntity() { return true; } isBlankNodeEntity() { return false; } hasTypeCriteria() { return false; } getDefaultLabelProperty() { return undefined; } getOrder() { return undefined; } getTooltip() { return undefined; } getDatasource() { return null; } getTreeChildrenDatasource() { return null; } getTreeRootsDatasource() { return null; } getHighlightedIcon() { return ""; } getParents() { return []; } getChildren() { return []; } couldBeSkosConcept() { return false; } } export class SpecialSHACLSpecificationEntityRegistry { /** * The Singleton's constructor should always be private to prevent direct * construction calls with the `new` operator. */ constructor() { this.registry = new Map(); this.registry.set(SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_OTHER, new SpecialSHACLSpecificationEntity(SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_OTHER, "fa-solid fa-ellipsis", "Other", function (n3store, shapeUri) { // this is in range if nothing else is in range let graph = new Model(n3store); return (!graph.hasTriple(factory.namedNode(shapeUri), SH.NODE, null) && !graph.hasTriple(factory.namedNode(shapeUri), SH.CLASS, null) && !graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.DATE) && !graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.DATE_TIME) && !graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.GYEAR) && !graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, GEOSPARQL.WKT_LITERAL) && !graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.STRING) && !graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, RDF.LANG_STRING)); })); this.registry.set(SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_DATES, new SpecialSHACLSpecificationEntity(SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_DATES, "fa-solid fa-calendar", "Date", function (n3store, shapeUri) { let graph = new Model(n3store); let dt = graph.readSingleProperty(factory.namedNode(shapeUri), SH.DATATYPE); return dt && DatatypeRegistry.asDatatype(dt).isDateDatatype(); })); this.registry.set(SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_LOCATION, new SpecialSHACLSpecificationEntity(SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_LOCATION, "fa-solid fa-map-location-dot", "Location", function (n3store, shapeUri) { let graph = new Model(n3store); return graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, GEOSPARQL.WKT_LITERAL); })); this.registry.set(SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_TEXT, new SpecialSHACLSpecificationEntity(SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_TEXT, "fa-solid fa-font", "Text", function (n3store, shapeUri) { let graph = new Model(n3store); return (graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.STRING) || graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, RDF.LANG_STRING) || // no datatype but we know it is a Literal (graph.hasTriple(factory.namedNode(shapeUri), SH.NODE_KIND, SH.LITERAL) && (!graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, null) || (!graph.readSingleProperty(factory.namedNode(shapeUri), SH.DATATYPE)?.value.startsWith("http://www.w3.org/2001/XMLSchema#") && !graph.readSingleProperty(factory.namedNode(shapeUri), SH.DATATYPE)?.value.startsWith("http://www.opengis.net/ont/geosparql#"))))); })); this.registry.set(SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_NUMBER, new SpecialSHACLSpecificationEntity(SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_NUMBER, "fa-solid fa-1", "Number", function (n3store, shapeUri) { let graph = new Model(n3store); let dt = graph.readSingleProperty(factory.namedNode(shapeUri), SH.DATATYPE); return dt && DatatypeRegistry.asDatatype(dt).isNumberDatatype(); })); } /** * The static method that controls the access to the singleton instance. * * This implementation let you subclass the Singleton class while keeping * just one instance of each subclass around. */ static getInstance() { if (!SpecialSHACLSpecificationEntityRegistry.instance) { SpecialSHACLSpecificationEntityRegistry.instance = new SpecialSHACLSpecificationEntityRegistry(); } return SpecialSHACLSpecificationEntityRegistry.instance; } getRegistry() { return this.registry; } } SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_DATES = "http://special/Z_Date"; SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_LOCATION = "http://special/Z_Location"; SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_TEXT = "http://special/Z_Text"; SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_NUMBER = "http://special/Z_Number"; SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_OTHER = "http://special/ZZ_Other"; SpecialSHACLSpecificationEntityRegistry.instance = new SpecialSHACLSpecificationEntityRegistry(); //# sourceMappingURL=SHACLSpecificationEntity.js.map