UNPKG

@ulb-darmstadt/shacl-form

Version:
106 lines (100 loc) 5.4 kB
import { BlankNode, Literal, NamedNode, Quad } from 'n3' import { Term } from '@rdfjs/types' import { ShaclNode } from "./node" import { ShaclProperty, createPropertyInstance } from "./property" import { Config } from './config' import { PREFIX_SHACL, RDF_PREDICATE_TYPE, SHACL_PREDICATE_CLASS, SHACL_PREDICATE_TARGET_CLASS, SHACL_PREDICATE_NODE_KIND, SHACL_OBJECT_IRI } from './constants' import { findLabel, removePrefixes } from './util' import { ShaclPropertyTemplate } from './property-template' import { Editor, InputListEntry } from './theme' export function createShaclOrConstraint(options: Term[], context: ShaclNode | ShaclProperty, config: Config): HTMLElement { const constraintElement = document.createElement('div') constraintElement.classList.add('shacl-or-constraint') const optionElements: InputListEntry[] = [] optionElements.push({ label: '--- please choose ---', value: '' }) if (context instanceof ShaclNode) { const properties: ShaclProperty[] = [] // expect options to be shacl properties for (let i = 0; i < options.length; i++) { const property = new ShaclProperty(options[i] as NamedNode | BlankNode, context, config) properties.push(property) optionElements.push({ label: property.template.label, value: i.toString() }) } const editor = config.theme.createListEditor('Please choose', null, false, optionElements) const select = editor.querySelector('.editor') as Editor select.onchange = () => { if (select.value) { constraintElement.replaceWith(properties[parseInt(select.value)]) } } constraintElement.appendChild(editor) } else { const values: Quad[][] = [] for (let i = 0; i < options.length; i++) { const quads = config.shapesGraph.getQuads(options[i], null, null, null) if (quads.length) { values.push(quads) optionElements.push({ label: findLabel(quads, config.languages) || (removePrefixes(quads[0].predicate.value, config.prefixes) + ' = ' + removePrefixes(quads[0].object.value, config.prefixes)), value: i.toString() }) } } const editor = config.theme.createListEditor(context.template.label + '?', null, false, optionElements, context.template) const select = editor.querySelector('.editor') as Editor select.onchange = () => { if (select.value) { constraintElement.replaceWith(createPropertyInstance(context.template.clone().merge(values[parseInt(select.value)]), undefined, true)) } } constraintElement.appendChild(editor) } return constraintElement } export function resolveShaclOrConstraint(template: ShaclPropertyTemplate, value: Term): ShaclPropertyTemplate { if (!template.shaclOr) { console.warn('can\'t resolve sh:or because template has no options', template) return template } if (value instanceof Literal) { // value is a literal, try to resolve sh:or by matching on given value datatype const valueType = value.datatype for (const subject of template.shaclOr) { const options = template.config.shapesGraph.getQuads(subject, null, null, null) for (const quad of options) { if (quad.predicate.value === `${PREFIX_SHACL}datatype` && quad.object.equals(valueType)) { return template.clone().merge(options) } } } } else { // value is a NamedNode or BlankNode, try to resolve sh:or by matching rdf:type of given value with sh:node or sh:class in data graph or shapes graph let types = template.config.dataGraph.getObjects(value, RDF_PREDICATE_TYPE, null) types.push(...template.config.shapesGraph.getObjects(value, RDF_PREDICATE_TYPE, null)) for (const subject of template.shaclOr) { const options = template.config.shapesGraph.getQuads(subject, null, null, null) for (const quad of options) { if (types.length > 0) { // try to find matching sh:node in sh:or values if (quad.predicate.value === `${PREFIX_SHACL}node`) { for (const type of types) { if (template.config.shapesGraph.getQuads(quad.object, SHACL_PREDICATE_TARGET_CLASS, type, null).length > 0) { return template.clone().merge(options) } } } // try to find matching sh:class in sh:or values if (quad.predicate.equals(SHACL_PREDICATE_CLASS)) { for (const type of types) { if (quad.object.equals(type)) { return template.clone().merge(options) } } } } else if (quad.predicate.equals(SHACL_PREDICATE_NODE_KIND) && quad.object.equals(SHACL_OBJECT_IRI)) { // if sh:nodeKind is sh:IRI, just use that return template.clone().merge(options) } } } } console.error('couldn\'t resolve sh:or for value', value) return template }