@oml/owl 0.9.0 → 0.10.0
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/out/owl/owl-mapper.d.ts +1 -1
- package/out/owl/owl-mapper.js +47 -42
- package/out/owl/owl-mapper.js.map +1 -1
- package/out/owl/owl-service.d.ts +6 -1
- package/out/owl/owl-service.js +89 -13
- package/out/owl/owl-service.js.map +1 -1
- package/out/owl/owl-shacl.js +13 -5
- package/out/owl/owl-shacl.js.map +1 -1
- package/package.json +2 -2
- package/src/owl/owl-mapper.ts +60 -53
- package/src/owl/owl-service.ts +95 -15
- package/src/owl/owl-shacl.ts +17 -8
package/src/owl/owl-mapper.ts
CHANGED
|
@@ -257,8 +257,8 @@ const BUILT_IN_ONTOLOGIES = new Set([
|
|
|
257
257
|
'http://www.w3.org/2003/11/swrlb',
|
|
258
258
|
]);
|
|
259
259
|
|
|
260
|
-
const { namedNode, literal, quad } = DataFactory;
|
|
261
|
-
type TermNode = ReturnType<typeof namedNode>;
|
|
260
|
+
const { blankNode, namedNode, literal, quad } = DataFactory;
|
|
261
|
+
type TermNode = ReturnType<typeof namedNode> | ReturnType<typeof blankNode>;
|
|
262
262
|
|
|
263
263
|
function fnv1a(input: string): string {
|
|
264
264
|
let hash = 2166136261;
|
|
@@ -578,24 +578,24 @@ export class Oml2OwlMapper {
|
|
|
578
578
|
const sourceVar = this.toSwrlVariable('s', triples);
|
|
579
579
|
const targetVar = this.toSwrlVariable('t', triples);
|
|
580
580
|
|
|
581
|
-
const classAtom =
|
|
581
|
+
const classAtom = blankNode();
|
|
582
582
|
triples.push(this.quadWithGraph(classAtom, namedNode(RDF.type), namedNode(SWRL.ClassAtom)));
|
|
583
583
|
triples.push(this.quadWithGraph(classAtom, namedNode(SWRL.classPredicate), namedNode(relationEntityIri)));
|
|
584
584
|
triples.push(this.quadWithGraph(classAtom, namedNode(SWRL.argument1), relationVar));
|
|
585
585
|
|
|
586
|
-
const sourceAtom =
|
|
586
|
+
const sourceAtom = blankNode();
|
|
587
587
|
triples.push(this.quadWithGraph(sourceAtom, namedNode(RDF.type), namedNode(SWRL.IndividualPropertyAtom)));
|
|
588
588
|
triples.push(this.quadWithGraph(sourceAtom, namedNode(SWRL.propertyPredicate), namedNode(OML.hasSource)));
|
|
589
589
|
triples.push(this.quadWithGraph(sourceAtom, namedNode(SWRL.argument1), relationVar));
|
|
590
590
|
triples.push(this.quadWithGraph(sourceAtom, namedNode(SWRL.argument2), sourceVar));
|
|
591
591
|
|
|
592
|
-
const targetAtom =
|
|
592
|
+
const targetAtom = blankNode();
|
|
593
593
|
triples.push(this.quadWithGraph(targetAtom, namedNode(RDF.type), namedNode(SWRL.IndividualPropertyAtom)));
|
|
594
594
|
triples.push(this.quadWithGraph(targetAtom, namedNode(SWRL.propertyPredicate), namedNode(OML.hasTarget)));
|
|
595
595
|
triples.push(this.quadWithGraph(targetAtom, namedNode(SWRL.argument1), relationVar));
|
|
596
596
|
triples.push(this.quadWithGraph(targetAtom, namedNode(SWRL.argument2), targetVar));
|
|
597
597
|
|
|
598
|
-
const headAtom =
|
|
598
|
+
const headAtom = blankNode();
|
|
599
599
|
triples.push(this.quadWithGraph(headAtom, namedNode(RDF.type), namedNode(SWRL.IndividualPropertyAtom)));
|
|
600
600
|
triples.push(this.quadWithGraph(headAtom, namedNode(SWRL.propertyPredicate), namedNode(forwardIri)));
|
|
601
601
|
triples.push(this.quadWithGraph(headAtom, namedNode(SWRL.argument1), sourceVar));
|
|
@@ -635,7 +635,7 @@ export class Oml2OwlMapper {
|
|
|
635
635
|
if (predicate.type.ref && isScalar(predicate.type.ref)) {
|
|
636
636
|
const argument = this.toSwrlDArgument(predicate.argument, ctx, triples);
|
|
637
637
|
if (!argument) return [];
|
|
638
|
-
const atom =
|
|
638
|
+
const atom = blankNode();
|
|
639
639
|
triples.push(this.quadWithGraph(atom, namedNode(RDF.type), namedNode(SWRL.DataRangeAtom)));
|
|
640
640
|
triples.push(this.quadWithGraph(atom, namedNode(SWRL.dataRange), namedNode(typeIri)));
|
|
641
641
|
triples.push(this.quadWithGraph(atom, namedNode(SWRL.argument1), argument));
|
|
@@ -644,7 +644,7 @@ export class Oml2OwlMapper {
|
|
|
644
644
|
|
|
645
645
|
const argument = this.toSwrlIArgument(predicate.argument, ctx, triples);
|
|
646
646
|
if (!argument) return [];
|
|
647
|
-
const atom =
|
|
647
|
+
const atom = blankNode();
|
|
648
648
|
triples.push(this.quadWithGraph(atom, namedNode(RDF.type), namedNode(SWRL.ClassAtom)));
|
|
649
649
|
triples.push(this.quadWithGraph(atom, namedNode(SWRL.classPredicate), namedNode(typeIri)));
|
|
650
650
|
triples.push(this.quadWithGraph(atom, namedNode(SWRL.argument1), argument));
|
|
@@ -658,18 +658,18 @@ export class Oml2OwlMapper {
|
|
|
658
658
|
const argument2 = this.toSwrlIArgument(predicate.argument2, ctx, triples);
|
|
659
659
|
if (!typeIri || !argument || !argument1 || !argument2) return [];
|
|
660
660
|
|
|
661
|
-
const typeAtom =
|
|
661
|
+
const typeAtom = blankNode();
|
|
662
662
|
triples.push(this.quadWithGraph(typeAtom, namedNode(RDF.type), namedNode(SWRL.ClassAtom)));
|
|
663
663
|
triples.push(this.quadWithGraph(typeAtom, namedNode(SWRL.classPredicate), namedNode(typeIri)));
|
|
664
664
|
triples.push(this.quadWithGraph(typeAtom, namedNode(SWRL.argument1), argument));
|
|
665
665
|
|
|
666
|
-
const sourceAtom =
|
|
666
|
+
const sourceAtom = blankNode();
|
|
667
667
|
triples.push(this.quadWithGraph(sourceAtom, namedNode(RDF.type), namedNode(SWRL.IndividualPropertyAtom)));
|
|
668
668
|
triples.push(this.quadWithGraph(sourceAtom, namedNode(SWRL.propertyPredicate), namedNode(OML.hasSource)));
|
|
669
669
|
triples.push(this.quadWithGraph(sourceAtom, namedNode(SWRL.argument1), argument));
|
|
670
670
|
triples.push(this.quadWithGraph(sourceAtom, namedNode(SWRL.argument2), argument1));
|
|
671
671
|
|
|
672
|
-
const targetAtom =
|
|
672
|
+
const targetAtom = blankNode();
|
|
673
673
|
triples.push(this.quadWithGraph(targetAtom, namedNode(RDF.type), namedNode(SWRL.IndividualPropertyAtom)));
|
|
674
674
|
triples.push(this.quadWithGraph(targetAtom, namedNode(SWRL.propertyPredicate), namedNode(OML.hasTarget)));
|
|
675
675
|
triples.push(this.quadWithGraph(targetAtom, namedNode(SWRL.argument1), argument));
|
|
@@ -686,9 +686,7 @@ export class Oml2OwlMapper {
|
|
|
686
686
|
const isDataPredicate =
|
|
687
687
|
(predicate.property.ref && isScalarProperty(predicate.property.ref)) ||
|
|
688
688
|
(predicate.property.ref && isAnnotationProperty(predicate.property.ref) && Boolean(predicate.argument2.literal));
|
|
689
|
-
const atom =
|
|
690
|
-
? skolemize(ctx.namespace, 'rule-atom', atomSeed, 'property', 'data', propertyIri, this.termKey(argument1))
|
|
691
|
-
: skolemize(ctx.namespace, 'rule-atom', atomSeed, 'property', 'object', propertyIri, this.termKey(argument1));
|
|
689
|
+
const atom = blankNode();
|
|
692
690
|
if (isDataPredicate) {
|
|
693
691
|
const argument2 = this.toSwrlDArgument(predicate.argument2, ctx, triples);
|
|
694
692
|
if (!argument2) return [];
|
|
@@ -711,7 +709,7 @@ export class Oml2OwlMapper {
|
|
|
711
709
|
const argument1 = this.toSwrlIArgument(predicate.argument1, ctx, triples);
|
|
712
710
|
const argument2 = this.toSwrlIArgument(predicate.argument2, ctx, triples);
|
|
713
711
|
if (!argument1 || !argument2) return [];
|
|
714
|
-
const atom =
|
|
712
|
+
const atom = blankNode();
|
|
715
713
|
triples.push(this.quadWithGraph(atom, namedNode(RDF.type), namedNode(SWRL.SameIndividualAtom)));
|
|
716
714
|
triples.push(this.quadWithGraph(atom, namedNode(SWRL.argument1), argument1));
|
|
717
715
|
triples.push(this.quadWithGraph(atom, namedNode(SWRL.argument2), argument2));
|
|
@@ -722,7 +720,7 @@ export class Oml2OwlMapper {
|
|
|
722
720
|
const argument1 = this.toSwrlIArgument(predicate.argument1, ctx, triples);
|
|
723
721
|
const argument2 = this.toSwrlIArgument(predicate.argument2, ctx, triples);
|
|
724
722
|
if (!argument1 || !argument2) return [];
|
|
725
|
-
const atom =
|
|
723
|
+
const atom = blankNode();
|
|
726
724
|
triples.push(this.quadWithGraph(atom, namedNode(RDF.type), namedNode(SWRL.DifferentIndividualsAtom)));
|
|
727
725
|
triples.push(this.quadWithGraph(atom, namedNode(SWRL.argument1), argument1));
|
|
728
726
|
triples.push(this.quadWithGraph(atom, namedNode(SWRL.argument2), argument2));
|
|
@@ -735,7 +733,7 @@ export class Oml2OwlMapper {
|
|
|
735
733
|
const argumentsList = predicate.arguments
|
|
736
734
|
.map((argument) => this.toSwrlDArgument(argument, ctx, triples))
|
|
737
735
|
.filter((argument): argument is Quad_Object => Boolean(argument));
|
|
738
|
-
const atom =
|
|
736
|
+
const atom = blankNode();
|
|
739
737
|
triples.push(this.quadWithGraph(atom, namedNode(RDF.type), namedNode(SWRL.BuiltinAtom)));
|
|
740
738
|
triples.push(this.quadWithGraph(atom, namedNode(SWRL.builtin), namedNode(builtInIri)));
|
|
741
739
|
triples.push(this.quadWithGraph(atom, namedNode(SWRL.arguments), this.createRdfList(ctx, argumentsList, triples, `rule-builtin-args|${atomSeed}|${builtInIri}`)));
|
|
@@ -836,7 +834,7 @@ export class Oml2OwlMapper {
|
|
|
836
834
|
|
|
837
835
|
private mapAnonymousInstance(
|
|
838
836
|
instance: AnonymousInstance,
|
|
839
|
-
node:
|
|
837
|
+
node: TermNode,
|
|
840
838
|
ctx: MappingContext,
|
|
841
839
|
triples: Quad[],
|
|
842
840
|
source?: TermNode,
|
|
@@ -947,7 +945,7 @@ export class Oml2OwlMapper {
|
|
|
947
945
|
.filter((iri): iri is string => Boolean(iri))
|
|
948
946
|
.map((iri) => namedNode(iri));
|
|
949
947
|
if (!instanceNodes.length) return;
|
|
950
|
-
const listHead = this.
|
|
948
|
+
const listHead = this.createBlankNodeRdfList(instanceNodes, triples);
|
|
951
949
|
triples.push(this.quadWithGraph(classNode, namedNode(OWL.oneOf), listHead));
|
|
952
950
|
}
|
|
953
951
|
|
|
@@ -963,9 +961,8 @@ export class Oml2OwlMapper {
|
|
|
963
961
|
.map((lit) => this.toLiteral(lit, ctx))
|
|
964
962
|
.filter((node): node is Quad_Object => Boolean(node));
|
|
965
963
|
if (!literalNodes.length) return;
|
|
966
|
-
const
|
|
967
|
-
const
|
|
968
|
-
const dataRangeNode = skolemize(ctx.namespace, 'datatype-enum', scalarNode.value, literalSignature);
|
|
964
|
+
const listHead = this.createBlankNodeRdfList(literalNodes, triples);
|
|
965
|
+
const dataRangeNode = blankNode();
|
|
969
966
|
triples.push(this.quadWithGraph(dataRangeNode, namedNode(RDF.type), namedNode(RDFS.Datatype)));
|
|
970
967
|
triples.push(this.quadWithGraph(dataRangeNode, namedNode(OWL.oneOf), listHead));
|
|
971
968
|
triples.push(this.quadWithGraph(scalarNode, namedNode(OWL.equivalentClass), dataRangeNode));
|
|
@@ -1005,7 +1002,7 @@ export class Oml2OwlMapper {
|
|
|
1005
1002
|
axiom: ScalarEquivalenceAxiom,
|
|
1006
1003
|
ctx: MappingContext,
|
|
1007
1004
|
triples: Quad[],
|
|
1008
|
-
):
|
|
1005
|
+
): TermNode[] {
|
|
1009
1006
|
const facets: Array<{ iri: string; value: Quad_Object }> = [];
|
|
1010
1007
|
|
|
1011
1008
|
axiom.length.forEach((value) => {
|
|
@@ -1061,10 +1058,10 @@ export class Oml2OwlMapper {
|
|
|
1061
1058
|
|
|
1062
1059
|
return datatypes.map((datatypeIri) => {
|
|
1063
1060
|
const facetSignature = facets.map((facet) => `${facet.iri}=${this.termKey(facet.value)}`).join('|');
|
|
1064
|
-
const restrictionNode =
|
|
1061
|
+
const restrictionNode = blankNode();
|
|
1065
1062
|
triples.push(this.quadWithGraph(restrictionNode, namedNode(OWL.onDatatype), namedNode(datatypeIri)));
|
|
1066
1063
|
const restrictionItems = facets.map((facet, index) => {
|
|
1067
|
-
const facetNode =
|
|
1064
|
+
const facetNode = blankNode();
|
|
1068
1065
|
triples.push(this.quadWithGraph(facetNode, namedNode(facet.iri), facet.value));
|
|
1069
1066
|
return facetNode;
|
|
1070
1067
|
});
|
|
@@ -1078,7 +1075,7 @@ export class Oml2OwlMapper {
|
|
|
1078
1075
|
axiom: PropertyRestrictionAxiom,
|
|
1079
1076
|
ctx: MappingContext,
|
|
1080
1077
|
triples: Quad[],
|
|
1081
|
-
):
|
|
1078
|
+
): TermNode | undefined {
|
|
1082
1079
|
if (isPropertyRangeRestrictionAxiom(axiom)) {
|
|
1083
1080
|
return this.mapRangeRestriction(axiom, ctx, triples);
|
|
1084
1081
|
}
|
|
@@ -1098,11 +1095,11 @@ export class Oml2OwlMapper {
|
|
|
1098
1095
|
axiom: PropertyRangeRestrictionAxiom,
|
|
1099
1096
|
ctx: MappingContext,
|
|
1100
1097
|
triples: Quad[],
|
|
1101
|
-
):
|
|
1098
|
+
): TermNode | undefined {
|
|
1102
1099
|
const propertyIri = this.resolveIri(axiom.property, ctx);
|
|
1103
1100
|
const rangeIri = this.resolveIri(axiom.range, ctx);
|
|
1104
1101
|
if (!propertyIri || !rangeIri) return undefined;
|
|
1105
|
-
const node =
|
|
1102
|
+
const node = blankNode();
|
|
1106
1103
|
|
|
1107
1104
|
triples.push(this.quadWithGraph(node, namedNode(RDF.type), namedNode(OWL.Restriction)));
|
|
1108
1105
|
triples.push(this.quadWithGraph(node, namedNode(OWL.onProperty), namedNode(propertyIri)));
|
|
@@ -1115,12 +1112,12 @@ export class Oml2OwlMapper {
|
|
|
1115
1112
|
axiom: PropertyCardinalityRestrictionAxiom,
|
|
1116
1113
|
ctx: MappingContext,
|
|
1117
1114
|
triples: Quad[],
|
|
1118
|
-
):
|
|
1115
|
+
): TermNode | undefined {
|
|
1119
1116
|
const propertyIri = this.resolveIri(axiom.property, ctx);
|
|
1120
1117
|
if (!propertyIri) return undefined;
|
|
1121
1118
|
const resolvedProperty = (axiom.property as any)?.ref as SemanticProperty | undefined;
|
|
1122
1119
|
const rangeIri = this.resolveIri(axiom.range, ctx) ?? '';
|
|
1123
|
-
const node =
|
|
1120
|
+
const node = blankNode();
|
|
1124
1121
|
triples.push(this.quadWithGraph(node, namedNode(RDF.type), namedNode(OWL.Restriction)));
|
|
1125
1122
|
triples.push(this.quadWithGraph(node, namedNode(OWL.onProperty), namedNode(propertyIri)));
|
|
1126
1123
|
if (rangeIri) {
|
|
@@ -1141,15 +1138,10 @@ export class Oml2OwlMapper {
|
|
|
1141
1138
|
axiom: PropertyValueRestrictionAxiom,
|
|
1142
1139
|
ctx: MappingContext,
|
|
1143
1140
|
triples: Quad[],
|
|
1144
|
-
):
|
|
1141
|
+
): TermNode | undefined {
|
|
1145
1142
|
const propertyIri = this.resolveIri(axiom.property, ctx);
|
|
1146
1143
|
if (!propertyIri) return undefined;
|
|
1147
|
-
const
|
|
1148
|
-
? this.literalKey(axiom.literalValue, ctx)
|
|
1149
|
-
: axiom.referencedValue
|
|
1150
|
-
? this.resolveIri(axiom.referencedValue, ctx) ?? ''
|
|
1151
|
-
: 'contained';
|
|
1152
|
-
const node = skolemize(ctx.namespace, 'restriction', propertyIri, 'hasValue', valueSeed);
|
|
1144
|
+
const node = blankNode();
|
|
1153
1145
|
triples.push(this.quadWithGraph(node, namedNode(RDF.type), namedNode(OWL.Restriction)));
|
|
1154
1146
|
triples.push(this.quadWithGraph(node, namedNode(OWL.onProperty), namedNode(propertyIri)));
|
|
1155
1147
|
|
|
@@ -1175,10 +1167,10 @@ export class Oml2OwlMapper {
|
|
|
1175
1167
|
axiom: PropertySelfRestrictionAxiom,
|
|
1176
1168
|
ctx: MappingContext,
|
|
1177
1169
|
triples: Quad[],
|
|
1178
|
-
):
|
|
1170
|
+
): TermNode | undefined {
|
|
1179
1171
|
const propertyIri = this.resolveIri(axiom.property, ctx);
|
|
1180
1172
|
if (!propertyIri) return undefined;
|
|
1181
|
-
const node =
|
|
1173
|
+
const node = blankNode();
|
|
1182
1174
|
triples.push(this.quadWithGraph(node, namedNode(RDF.type), namedNode(OWL.Restriction)));
|
|
1183
1175
|
triples.push(this.quadWithGraph(node, namedNode(OWL.onProperty), namedNode(propertyIri)));
|
|
1184
1176
|
triples.push(this.quadWithGraph(node, namedNode(OWL.hasSelf), literal('true', namedNode(XSD.boolean))));
|
|
@@ -1261,19 +1253,40 @@ export class Oml2OwlMapper {
|
|
|
1261
1253
|
items: Quad_Object[],
|
|
1262
1254
|
triples: Quad[],
|
|
1263
1255
|
listSeed: string,
|
|
1264
|
-
):
|
|
1256
|
+
): TermNode {
|
|
1265
1257
|
if (!items.length) {
|
|
1266
1258
|
return namedNode(RDF.nil);
|
|
1267
1259
|
}
|
|
1268
|
-
const
|
|
1269
|
-
const head = skolemize(ctx.namespace, 'list', base, '0');
|
|
1260
|
+
const head = blankNode();
|
|
1270
1261
|
let current = head;
|
|
1271
1262
|
items.forEach((item, index) => {
|
|
1272
1263
|
triples.push(this.quadWithGraph(current, namedNode(RDF.first), item));
|
|
1273
1264
|
if (index === items.length - 1) {
|
|
1274
1265
|
triples.push(this.quadWithGraph(current, namedNode(RDF.rest), namedNode(RDF.nil)));
|
|
1275
1266
|
} else {
|
|
1276
|
-
const next =
|
|
1267
|
+
const next = blankNode();
|
|
1268
|
+
triples.push(this.quadWithGraph(current, namedNode(RDF.rest), next));
|
|
1269
|
+
current = next;
|
|
1270
|
+
}
|
|
1271
|
+
});
|
|
1272
|
+
return head;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
private createBlankNodeRdfList(
|
|
1276
|
+
items: Quad_Object[],
|
|
1277
|
+
triples: Quad[],
|
|
1278
|
+
): ReturnType<typeof blankNode> | ReturnType<typeof namedNode> {
|
|
1279
|
+
if (!items.length) {
|
|
1280
|
+
return namedNode(RDF.nil);
|
|
1281
|
+
}
|
|
1282
|
+
const head = blankNode();
|
|
1283
|
+
let current = head;
|
|
1284
|
+
items.forEach((item, index) => {
|
|
1285
|
+
triples.push(this.quadWithGraph(current, namedNode(RDF.first), item));
|
|
1286
|
+
if (index === items.length - 1) {
|
|
1287
|
+
triples.push(this.quadWithGraph(current, namedNode(RDF.rest), namedNode(RDF.nil)));
|
|
1288
|
+
} else {
|
|
1289
|
+
const next = blankNode();
|
|
1277
1290
|
triples.push(this.quadWithGraph(current, namedNode(RDF.rest), next));
|
|
1278
1291
|
current = next;
|
|
1279
1292
|
}
|
|
@@ -1286,7 +1299,7 @@ export class Oml2OwlMapper {
|
|
|
1286
1299
|
items: Quad_Object[],
|
|
1287
1300
|
triples: Quad[],
|
|
1288
1301
|
listSeed: string,
|
|
1289
|
-
):
|
|
1302
|
+
): TermNode {
|
|
1290
1303
|
const head = this.createRdfList(ctx, items, triples, listSeed);
|
|
1291
1304
|
if (head.value === RDF.nil) {
|
|
1292
1305
|
return head;
|
|
@@ -1295,12 +1308,11 @@ export class Oml2OwlMapper {
|
|
|
1295
1308
|
while (current.value !== RDF.nil) {
|
|
1296
1309
|
triples.push(this.quadWithGraph(current, namedNode(RDF.type), namedNode(SWRL.AtomList)));
|
|
1297
1310
|
const next = triples.find(
|
|
1298
|
-
(quad) => quad.subject.
|
|
1299
|
-
&& quad.subject.value === current.value
|
|
1311
|
+
(quad) => quad.subject.value === current.value
|
|
1300
1312
|
&& quad.predicate.value === RDF.rest
|
|
1301
|
-
&& quad.object.termType === 'NamedNode',
|
|
1313
|
+
&& (quad.object.termType === 'NamedNode' || quad.object.termType === 'BlankNode'),
|
|
1302
1314
|
)?.object;
|
|
1303
|
-
if (!next || next.termType !== 'NamedNode') {
|
|
1315
|
+
if (!next || (next.termType !== 'NamedNode' && next.termType !== 'BlankNode')) {
|
|
1304
1316
|
break;
|
|
1305
1317
|
}
|
|
1306
1318
|
current = next;
|
|
@@ -1437,11 +1449,6 @@ export class Oml2OwlMapper {
|
|
|
1437
1449
|
return `${term.termType}:${term.value}`;
|
|
1438
1450
|
}
|
|
1439
1451
|
|
|
1440
|
-
private literalKey(value: Literal, ctx: MappingContext): string {
|
|
1441
|
-
const term = this.toLiteral(value, ctx);
|
|
1442
|
-
return term ? this.termKey(term) : '';
|
|
1443
|
-
}
|
|
1444
|
-
|
|
1445
1452
|
private toLiteral(value: Literal, ctx: MappingContext): Quad_Object | undefined {
|
|
1446
1453
|
if (isBooleanLiteral(value)) {
|
|
1447
1454
|
return literal(String(value.value), namedNode(XSD.boolean));
|
package/src/owl/owl-service.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { DocumentState, URI, type LangiumDocument } from 'langium';
|
|
4
4
|
import type { NamedNode, Quad } from 'n3';
|
|
5
|
-
import {
|
|
5
|
+
import { OmlIndex, getOntologyModelIndex, isDescription, isDescriptionBundle, isOntology, isVocabulary, isVocabularyBundle, type Import, type OmlServices, type Ontology } from '@oml/language';
|
|
6
6
|
import { Oml2OwlMapper } from './owl-mapper.js';
|
|
7
7
|
import { ReasoningStore } from './owl-store.js';
|
|
8
8
|
import { ABoxChainer, ABoxEntailmentCache, type ChainingResult } from './owl-abox.js';
|
|
@@ -33,7 +33,7 @@ export class ReasoningService {
|
|
|
33
33
|
private readonly aboxEntailmentCache: OwlABoxEntailmentState;
|
|
34
34
|
private readonly importGraph: OwlImportGraph;
|
|
35
35
|
private readonly sparqlService: OwlSparqlService;
|
|
36
|
-
private readonly ontologyModelIndex:
|
|
36
|
+
private readonly ontologyModelIndex: OmlIndex;
|
|
37
37
|
private readonly preparedModelAliases = new Map<string, string>();
|
|
38
38
|
private readonly activeDocuments = new Set<string>();
|
|
39
39
|
private readonly modelLoadInFlight = new Map<string, Promise<void>>();
|
|
@@ -166,11 +166,11 @@ export class ReasoningService {
|
|
|
166
166
|
return { complete, iterations, newQuadsCount, validationWarnings: [] };
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
onDocumentDeleted(document: LangiumDocument): void {
|
|
170
|
+
const modelUri = document.uri.toString();
|
|
170
171
|
const dependents = this.importGraph.dependentsOf(modelUri);
|
|
171
172
|
this.importGraph.remove(modelUri);
|
|
172
173
|
this.reasoningStore.retractModel(modelUri);
|
|
173
|
-
this.ontologyModelIndex.removeModel(modelUri);
|
|
174
174
|
this.tboxIndexCache.invalidateOwn(modelUri);
|
|
175
175
|
this.tboxIndexCache.invalidateMerged(modelUri);
|
|
176
176
|
this.aboxEntailmentCache.invalidate(modelUri);
|
|
@@ -241,6 +241,27 @@ export class ReasoningService {
|
|
|
241
241
|
await this.ensureContextDatasetReady(resolvedModelUri);
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
+
async getContextMemberLabelSnapshot(modelUri: string): Promise<Record<string, string>> {
|
|
245
|
+
const resolvedModelUri = this.resolveQueryModelUri(modelUri);
|
|
246
|
+
await this.ensureWorkspaceBuilt();
|
|
247
|
+
await this.ensureModelLoaded(resolvedModelUri);
|
|
248
|
+
await this.ensureContextDatasetReady(resolvedModelUri);
|
|
249
|
+
const modelUris = [resolvedModelUri, ...this.importGraph.dependenciesOf(resolvedModelUri)]
|
|
250
|
+
.map((uri) => this.resolveDocumentModelUri(uri))
|
|
251
|
+
.filter((uri): uri is string => Boolean(uri));
|
|
252
|
+
await this.ensureOntologyDocumentsLoaded(modelUris);
|
|
253
|
+
return this.ontologyModelIndex.getMemberLabelSnapshot(modelUris);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async getWorkspaceMemberLabelSnapshot(): Promise<Record<string, string>> {
|
|
257
|
+
await this.ensureWorkspaceBuilt();
|
|
258
|
+
const modelUris = [...new Set(this.preparedModelAliases.values())]
|
|
259
|
+
.map((uri) => this.resolveDocumentModelUri(uri))
|
|
260
|
+
.filter((uri): uri is string => Boolean(uri));
|
|
261
|
+
await this.ensureOntologyDocumentsLoaded(modelUris);
|
|
262
|
+
return this.ontologyModelIndex.getMemberLabelSnapshot(modelUris);
|
|
263
|
+
}
|
|
264
|
+
|
|
244
265
|
getContextIri(modelUri: string): string {
|
|
245
266
|
return this.resolveOntologyIriForModelUri(this.resolveQueryModelUri(modelUri));
|
|
246
267
|
}
|
|
@@ -248,16 +269,16 @@ export class ReasoningService {
|
|
|
248
269
|
setActiveDocuments(modelUris: string[]): void {
|
|
249
270
|
this.activeDocuments.clear();
|
|
250
271
|
for (const modelUri of modelUris) {
|
|
251
|
-
this.activeDocuments.add(modelUri);
|
|
272
|
+
this.activeDocuments.add(resolveCanonicalWorkspaceModelUri(modelUri));
|
|
252
273
|
}
|
|
253
274
|
}
|
|
254
275
|
|
|
255
276
|
markDocumentActive(modelUri: string): void {
|
|
256
|
-
this.activeDocuments.add(modelUri);
|
|
277
|
+
this.activeDocuments.add(resolveCanonicalWorkspaceModelUri(modelUri));
|
|
257
278
|
}
|
|
258
279
|
|
|
259
280
|
markDocumentInactive(modelUri: string): void {
|
|
260
|
-
this.activeDocuments.delete(modelUri);
|
|
281
|
+
this.activeDocuments.delete(resolveCanonicalWorkspaceModelUri(modelUri));
|
|
261
282
|
}
|
|
262
283
|
|
|
263
284
|
private extractImportedModelUris(ontology: Ontology): string[] {
|
|
@@ -360,11 +381,13 @@ export class ReasoningService {
|
|
|
360
381
|
if (!document) {
|
|
361
382
|
try {
|
|
362
383
|
document = await this.services.shared.workspace.LangiumDocuments.getOrCreateDocument(uri);
|
|
363
|
-
} catch {
|
|
384
|
+
} catch (error) {
|
|
364
385
|
// Another concurrent caller may have created it first.
|
|
365
386
|
document = this.services.shared.workspace.LangiumDocuments.getDocument(uri);
|
|
366
387
|
if (!document) {
|
|
367
|
-
|
|
388
|
+
const wrapped = new Error(`Unable to access model document '${modelUri}'.`);
|
|
389
|
+
(wrapped as any).cause = error;
|
|
390
|
+
throw wrapped;
|
|
368
391
|
}
|
|
369
392
|
}
|
|
370
393
|
}
|
|
@@ -384,6 +407,29 @@ export class ReasoningService {
|
|
|
384
407
|
}
|
|
385
408
|
}
|
|
386
409
|
|
|
410
|
+
private async ensureOntologyDocumentsLoaded(modelUris: Iterable<string>): Promise<void> {
|
|
411
|
+
const documents = this.services.shared.workspace.LangiumDocuments;
|
|
412
|
+
const builder = this.services.shared.workspace.DocumentBuilder;
|
|
413
|
+
const loadTargets: LangiumDocument[] = [];
|
|
414
|
+
for (const modelUri of new Set(modelUris)) {
|
|
415
|
+
const uri = URI.parse(modelUri);
|
|
416
|
+
const document = documents.getDocument(uri)
|
|
417
|
+
?? (typeof documents.getOrCreateDocument === 'function'
|
|
418
|
+
? await documents.getOrCreateDocument(uri)
|
|
419
|
+
: undefined);
|
|
420
|
+
if (!document) {
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
if ((document as any).state >= DocumentState.Linked) {
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
loadTargets.push(document);
|
|
427
|
+
}
|
|
428
|
+
if (loadTargets.length > 0) {
|
|
429
|
+
await builder.build(loadTargets, { validation: false });
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
387
433
|
private async ensureWorkspaceBuilt(): Promise<void> {
|
|
388
434
|
if (this.workspaceBuilt) {
|
|
389
435
|
return;
|
|
@@ -495,11 +541,12 @@ export class ReasoningService {
|
|
|
495
541
|
}
|
|
496
542
|
|
|
497
543
|
async countContextDatasetQuads(modelUri: string): Promise<number> {
|
|
544
|
+
const resolvedModelUri = this.resolveQueryModelUri(modelUri);
|
|
498
545
|
await this.ensureWorkspaceBuilt();
|
|
499
|
-
await this.ensureModelLoaded(
|
|
500
|
-
await this.ensureContextDatasetReady(
|
|
546
|
+
await this.ensureModelLoaded(resolvedModelUri);
|
|
547
|
+
await this.ensureContextDatasetReady(resolvedModelUri);
|
|
501
548
|
const store = this.reasoningStore.getStore();
|
|
502
|
-
const queryGraphs = this.resolveContextGraphs(
|
|
549
|
+
const queryGraphs = this.resolveContextGraphs(resolvedModelUri);
|
|
503
550
|
let total = 0;
|
|
504
551
|
for (const graph of queryGraphs) {
|
|
505
552
|
total += store.countQuads(null, null, null, graph);
|
|
@@ -508,16 +555,37 @@ export class ReasoningService {
|
|
|
508
555
|
}
|
|
509
556
|
|
|
510
557
|
private resolveWorkspaceModelUri(uri: string): string | undefined {
|
|
511
|
-
const
|
|
558
|
+
const canonicalUri = resolveCanonicalWorkspaceModelUri(uri);
|
|
559
|
+
const prepared = this.preparedModelAliases.get(uri) ?? this.preparedModelAliases.get(canonicalUri);
|
|
512
560
|
if (prepared) {
|
|
513
561
|
return prepared;
|
|
514
562
|
}
|
|
515
|
-
if (isWorkspaceModelUri(
|
|
516
|
-
return
|
|
563
|
+
if (isWorkspaceModelUri(canonicalUri)) {
|
|
564
|
+
return canonicalUri;
|
|
517
565
|
}
|
|
518
566
|
return this.ontologyModelIndex.resolveModelUri(uri);
|
|
519
567
|
}
|
|
520
568
|
|
|
569
|
+
private resolveDocumentModelUri(uri: string): string | undefined {
|
|
570
|
+
const normalizedUri = uri.trim();
|
|
571
|
+
if (!normalizedUri) {
|
|
572
|
+
return undefined;
|
|
573
|
+
}
|
|
574
|
+
if (isWorkspaceModelUri(normalizedUri)) {
|
|
575
|
+
return normalizedUri;
|
|
576
|
+
}
|
|
577
|
+
const indexed = this.ontologyModelIndex.resolveModelUri(normalizedUri);
|
|
578
|
+
if (indexed) {
|
|
579
|
+
return indexed;
|
|
580
|
+
}
|
|
581
|
+
const canonicalUri = resolveCanonicalWorkspaceModelUri(normalizedUri);
|
|
582
|
+
const prepared = this.preparedModelAliases.get(normalizedUri) ?? this.preparedModelAliases.get(canonicalUri);
|
|
583
|
+
if (!prepared || prepared === normalizedUri) {
|
|
584
|
+
return undefined;
|
|
585
|
+
}
|
|
586
|
+
return this.ontologyModelIndex.resolveModelUri(prepared) ?? (isWorkspaceModelUri(prepared) ? prepared : undefined);
|
|
587
|
+
}
|
|
588
|
+
|
|
521
589
|
private resolveLoadedDependencyOrder(modelUri: string): string[] {
|
|
522
590
|
const ordered = [...this.importGraph.dependenciesOf(modelUri), modelUri];
|
|
523
591
|
const seen = new Set<string>();
|
|
@@ -605,6 +673,18 @@ function isWorkspaceModelUri(modelUri: string): boolean {
|
|
|
605
673
|
}
|
|
606
674
|
}
|
|
607
675
|
|
|
676
|
+
export function resolveCanonicalWorkspaceModelUri(modelUri: string): string {
|
|
677
|
+
try {
|
|
678
|
+
const parsed = URI.parse(modelUri);
|
|
679
|
+
if (!parsed.path.toLowerCase().endsWith('.oml')) {
|
|
680
|
+
return modelUri;
|
|
681
|
+
}
|
|
682
|
+
return parsed.with({ query: '', fragment: '' }).toString();
|
|
683
|
+
} catch {
|
|
684
|
+
return modelUri;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
608
688
|
const BUILT_IN_ONTOLOGIES = new Set([
|
|
609
689
|
'http://www.w3.org/2001/XMLSchema',
|
|
610
690
|
'http://www.w3.org/1999/02/22-rdf-syntax-ns',
|
package/src/owl/owl-shacl.ts
CHANGED
|
@@ -36,6 +36,7 @@ type ParsedShaclNodeShape = {
|
|
|
36
36
|
targetClasses: Term[];
|
|
37
37
|
targetNodes: Term[];
|
|
38
38
|
columns: ParsedShaclColumn[];
|
|
39
|
+
includeEntailments: boolean;
|
|
39
40
|
};
|
|
40
41
|
|
|
41
42
|
type ConnectionLike = {
|
|
@@ -58,7 +59,7 @@ const SH_PATH = 'http://www.w3.org/ns/shacl#path';
|
|
|
58
59
|
const SH_PROPERTY = 'http://www.w3.org/ns/shacl#property';
|
|
59
60
|
const SH_TARGET_CLASS = 'http://www.w3.org/ns/shacl#targetClass';
|
|
60
61
|
const SH_TARGET_NODE = 'http://www.w3.org/ns/shacl#targetNode';
|
|
61
|
-
|
|
62
|
+
const OML_ENTAILED = 'http://opencaesar.io/oml#entailed';
|
|
62
63
|
export class ShaclService implements OwlShaclService {
|
|
63
64
|
constructor(
|
|
64
65
|
private readonly sparqlService: OwlSparqlService,
|
|
@@ -219,11 +220,15 @@ export function deriveSelectQueryFromShacl(shaclSource: string, graphIri: string
|
|
|
219
220
|
].join(' ');
|
|
220
221
|
const whereLines: string[] = [];
|
|
221
222
|
const graphLines: string[] = [];
|
|
223
|
+
const graphPattern = (pattern: string): string =>
|
|
224
|
+
nodeShape.includeEntailments
|
|
225
|
+
? `{ GRAPH <${escapeIriForSparql(graphIri)}> { ${pattern} } } UNION { GRAPH <${escapeIriForSparql(`${graphIri}__entailments`)}> { ${pattern} } }`
|
|
226
|
+
: `GRAPH <${escapeIriForSparql(graphIri)}> { ${pattern} }`;
|
|
222
227
|
|
|
223
228
|
if (nodeShape.targetClasses.length > 0) {
|
|
224
229
|
const values = nodeShape.targetClasses.map((term: Term) => `<${term.value}>`).join(' ');
|
|
225
230
|
whereLines.push(` VALUES ?__targetClass { ${values} }`);
|
|
226
|
-
graphLines.push('
|
|
231
|
+
graphLines.push(` ${graphPattern('?focus a ?__targetClass .')}`);
|
|
227
232
|
}
|
|
228
233
|
|
|
229
234
|
if (nodeShape.targetNodes.length > 0) {
|
|
@@ -232,12 +237,9 @@ export function deriveSelectQueryFromShacl(shaclSource: string, graphIri: string
|
|
|
232
237
|
}
|
|
233
238
|
|
|
234
239
|
for (const entry of variables) {
|
|
235
|
-
graphLines.push(` OPTIONAL {
|
|
240
|
+
graphLines.push(` OPTIONAL { ${graphPattern(`?focus <${entry.path}> ?${entry.sourceVariable} .`)} }`);
|
|
236
241
|
}
|
|
237
|
-
|
|
238
|
-
whereLines.push(` GRAPH <${escapeIriForSparql(graphIri)}> {`);
|
|
239
242
|
whereLines.push(...graphLines);
|
|
240
|
-
whereLines.push(' }');
|
|
241
243
|
|
|
242
244
|
const columnVariables = ['focus', ...variables.map((entry) => entry.variable)];
|
|
243
245
|
const columnLabels = new Map<string, string>([['focus', 'focus']]);
|
|
@@ -307,11 +309,14 @@ function parsePrimaryNodeShape(shapeQuads: readonly Quad[]): ParsedShaclNodeShap
|
|
|
307
309
|
};
|
|
308
310
|
})
|
|
309
311
|
.filter((column): column is ParsedShaclColumn => Boolean(column));
|
|
312
|
+
const includeEntailments = getObjects(shapesStore, shapeTerm, SH_PROPERTY)
|
|
313
|
+
.some((term) => isEntailedShape(shapesStore, term));
|
|
310
314
|
|
|
311
315
|
return {
|
|
312
316
|
targetClasses,
|
|
313
317
|
targetNodes,
|
|
314
318
|
columns,
|
|
319
|
+
includeEntailments,
|
|
315
320
|
};
|
|
316
321
|
}
|
|
317
322
|
|
|
@@ -344,8 +349,12 @@ function isDeactivatedShape(store: N3Store, subject: Term): boolean {
|
|
|
344
349
|
return getObjects(store, subject, SH_DEACTIVATED).some((term) => isTruthyLiteral(term));
|
|
345
350
|
}
|
|
346
351
|
|
|
347
|
-
function isTruthyLiteral(term: Term): boolean {
|
|
348
|
-
return term
|
|
352
|
+
function isTruthyLiteral(term: Term | undefined): boolean {
|
|
353
|
+
return term?.termType === 'Literal' && (term.value === 'true' || term.value === '1');
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function isEntailedShape(store: N3Store, subject: Term): boolean {
|
|
357
|
+
return getObjects(store, subject, OML_ENTAILED).some((term) => isTruthyLiteral(term));
|
|
349
358
|
}
|
|
350
359
|
|
|
351
360
|
function getObjects(store: N3Store, subject: Term, predicateIri: string): Term[] {
|