@ulb-darmstadt/shacl-form 1.7.1 → 1.7.3

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.
@@ -31,6 +31,7 @@ export declare class ShaclPropertyTemplate {
31
31
  languageIn: Term[] | undefined;
32
32
  datatype: NamedNode | undefined;
33
33
  hasValue: Term | undefined;
34
+ qualifiedValueShape: Term | undefined;
34
35
  owlImports: NamedNode[];
35
36
  config: Config;
36
37
  extendedShapes: NamedNode[] | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ulb-darmstadt/shacl-form",
3
- "version": "1.7.1",
3
+ "version": "1.7.3",
4
4
  "description": "SHACL form generator",
5
5
  "main": "dist/form-default.js",
6
6
  "module": "dist/form-default.js",
package/src/form.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { ShaclNode } from './node'
2
2
  import { Config } from './config'
3
3
  import { ClassInstanceProvider, Plugin, listPlugins, registerPlugin } from './plugin'
4
- import { Store, NamedNode, DataFactory } from 'n3'
5
- import { DCTERMS_PREDICATE_CONFORMS_TO, RDF_PREDICATE_TYPE, SHACL_OBJECT_NODE_SHAPE, SHACL_PREDICATE_TARGET_CLASS } from './constants'
4
+ import { Store, NamedNode, DataFactory, Quad } from 'n3'
5
+ import { DCTERMS_PREDICATE_CONFORMS_TO, PREFIX_SHACL, RDF_PREDICATE_TYPE, SHACL_OBJECT_NODE_SHAPE, SHACL_PREDICATE_TARGET_CLASS } from './constants'
6
6
  import { Editor, Theme } from './theme'
7
7
  import { serialize } from './serialize'
8
8
  import { Validator } from 'shacl-engine'
@@ -156,6 +156,10 @@ export class ShaclForm extends HTMLElement {
156
156
 
157
157
  this.config.shapesGraph.deleteGraph('')
158
158
  this.shape?.toRDF(this.config.shapesGraph)
159
+ if (this.shape) {
160
+ // add node target for validation. this is required in case of missing sh:targetClass in root shape
161
+ this.config.shapesGraph.add(new Quad(this.shape.shaclSubject, DataFactory.namedNode(PREFIX_SHACL + 'targetNode'), this.shape.nodeId, undefined))
162
+ }
159
163
  try {
160
164
  const dataset = this.config.shapesGraph
161
165
  const report = await new Validator(dataset, { details: true, factory: DataFactory }).validate({ dataset })
@@ -31,6 +31,9 @@ const mappers: Record<string, (template: ShaclPropertyTemplate, term: Term) => v
31
31
  [`${PREFIX_SHACL}languageIn`]: (template, term) => { template.languageIn = template.config.lists[term.value]; template.datatype = DataFactory.namedNode(PREFIX_RDF + 'langString') },
32
32
  [`${PREFIX_SHACL}defaultValue`]: (template, term) => { template.defaultValue = term },
33
33
  [`${PREFIX_SHACL}hasValue`]: (template, term) => { template.hasValue = term },
34
+ [`${PREFIX_SHACL}qualifiedValueShape`]: (template, term) => { template.qualifiedValueShape = term },
35
+ [`${PREFIX_SHACL}qualifiedMinCount`]: (template, term) => { template.minCount = parseInt(term.value) },
36
+ [`${PREFIX_SHACL}qualifiedMaxCount`]: (template, term) => { template.maxCount = parseInt(term.value) },
34
37
  [OWL_PREDICATE_IMPORTS.id]: (template, term) => { template.owlImports.push(term as NamedNode) },
35
38
  [SHACL_PREDICATE_CLASS.id]: (template, term) => {
36
39
  template.class = term as NamedNode
@@ -79,6 +82,7 @@ export class ShaclPropertyTemplate {
79
82
  languageIn: Term[] | undefined
80
83
  datatype: NamedNode | undefined
81
84
  hasValue: Term | undefined
85
+ qualifiedValueShape: Term | undefined
82
86
  owlImports: NamedNode[] = []
83
87
 
84
88
  config: Config
@@ -88,6 +92,9 @@ export class ShaclPropertyTemplate {
88
92
  this.parent = parent
89
93
  this.config = config
90
94
  this.merge(quads)
95
+ if (this.qualifiedValueShape) {
96
+ this.merge(config.shapesGraph.getQuads(this.qualifiedValueShape, null, null, null))
97
+ }
91
98
  }
92
99
 
93
100
  merge(quads: Quad[]): ShaclPropertyTemplate {
package/src/property.ts CHANGED
@@ -8,6 +8,7 @@ import { ShaclPropertyTemplate } from './property-template'
8
8
  import { Editor, fieldFactory } from './theme'
9
9
  import { toRDF } from './serialize'
10
10
  import { findPlugin } from './plugin'
11
+ import { RDF_PREDICATE_TYPE, SHACL_PREDICATE_TARGET_CLASS } from './constants'
11
12
 
12
13
  export class ShaclProperty extends HTMLElement {
13
14
  template: ShaclPropertyTemplate
@@ -46,6 +47,22 @@ export class ShaclProperty extends HTMLElement {
46
47
  const values = valueSubject ? config.dataGraph.getQuads(valueSubject, this.template.path, null, null) : []
47
48
  let valuesContainHasValue = false
48
49
  for (const value of values) {
50
+ // ignore values that do not conform to this property.
51
+ // this might be the case when there are multiple properties with the same sh:path in a NodeShape.
52
+ if (this.template.node) {
53
+ const targetClasses = config.shapesGraph.getObjects(this.template.node, SHACL_PREDICATE_TARGET_CLASS, null)
54
+ if (targetClasses.length > 0) {
55
+ let hasTargetClass = false
56
+ for (let i = 0; i < targetClasses.length && !hasTargetClass; i++) {
57
+ if (config.dataGraph.getQuads(value.object, RDF_PREDICATE_TYPE, targetClasses[i], null).length > 0) {
58
+ hasTargetClass = true
59
+ }
60
+ }
61
+ if (!hasTargetClass) {
62
+ continue
63
+ }
64
+ }
65
+ }
49
66
  this.addPropertyInstance(value.object)
50
67
  if (this.template.hasValue && value.object.equals(this.template.hasValue)) {
51
68
  valuesContainHasValue = true
package/src/util.ts CHANGED
@@ -85,22 +85,32 @@ function findClassInstancesFromOwlImports(clazz: NamedNode, context: ShaclNode |
85
85
  }
86
86
 
87
87
  export function findInstancesOf(clazz: NamedNode, template: ShaclPropertyTemplate, indent = 0): InputListEntry[] {
88
- // find instances in the shapes graph
89
- const instances: Term[] = template.config.shapesGraph.getSubjects(RDF_PREDICATE_TYPE, clazz, SHAPES_GRAPH)
90
- // find instances in the data graph
91
- instances.push(...template.config.dataGraph.getSubjects(RDF_PREDICATE_TYPE, clazz, null))
92
- // find instances in imported taxonomies
93
- findClassInstancesFromOwlImports(clazz, template, template.config.shapesGraph, instances)
94
-
95
- const entries = createInputListEntries(instances, template.config.shapesGraph, template.config.languages, indent)
96
- for (const subClass of template.config.shapesGraph.getSubjects(RDFS_PREDICATE_SUBCLASS_OF, clazz, null)) {
97
- entries.push(...findInstancesOf(subClass as NamedNode, template, indent + 1))
88
+ let instances: Term[]
89
+ // if template has sh:in, then just use that as class instances
90
+ if (template.shaclIn) {
91
+ const list = template.config.lists[template.shaclIn]
92
+ instances = list?.length ? list : []
93
+ } else {
94
+ // find instances in the shapes graph
95
+ instances = template.config.shapesGraph.getSubjects(RDF_PREDICATE_TYPE, clazz, SHAPES_GRAPH)
96
+ // find instances in the data graph
97
+ instances.push(...template.config.dataGraph.getSubjects(RDF_PREDICATE_TYPE, clazz, null))
98
+ // find instances in imported taxonomies
99
+ findClassInstancesFromOwlImports(clazz, template, template.config.shapesGraph, instances)
98
100
  }
99
- if (template.config.shapesGraph.getQuads(clazz, RDF_PREDICATE_TYPE, OWL_OBJECT_NAMED_INDIVIDUAL, null).length > 0) {
100
- entries.push(...createInputListEntries([ clazz ], template.config.shapesGraph, template.config.languages, indent))
101
- for (const subClass of template.config.shapesGraph.getSubjects(SKOS_PREDICATE_BROADER, clazz, null)) {
101
+
102
+ const entries = createInputListEntries(instances, template.config.shapesGraph, template.config.languages, indent)
103
+ // build inheritance tree only if sh:in is not defined
104
+ if (template.shaclIn === undefined) {
105
+ for (const subClass of template.config.shapesGraph.getSubjects(RDFS_PREDICATE_SUBCLASS_OF, clazz, null)) {
102
106
  entries.push(...findInstancesOf(subClass as NamedNode, template, indent + 1))
103
107
  }
108
+ if (template.config.shapesGraph.getQuads(clazz, RDF_PREDICATE_TYPE, OWL_OBJECT_NAMED_INDIVIDUAL, null).length > 0) {
109
+ entries.push(...createInputListEntries([ clazz ], template.config.shapesGraph, template.config.languages, indent))
110
+ for (const subClass of template.config.shapesGraph.getSubjects(SKOS_PREDICATE_BROADER, clazz, null)) {
111
+ entries.push(...findInstancesOf(subClass as NamedNode, template, indent + 1))
112
+ }
113
+ }
104
114
  }
105
115
  return entries
106
116
  }